From a1d71275f045b33c76cffc16d282ec72ec8661d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E6=9C=A8=E8=A6=81?= Date: Fri, 14 Jul 2023 14:28:36 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20CSV=E3=83=80=E3=82=A6=E3=83=B3=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=89=E7=94=BB=E9=9D=A2=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/.env.example | 1 + .../src/controller/master_mainte.py | 138 ++++++++++++- .../src/model/internal/master_mainte_csv.py | 4 + .../src/model/request/master_mainte_csvdl.py | 169 ++++++++++++++++ .../src/model/request/master_mainte_csvup.py | 2 +- .../view/inst_emp_csv_download_view_model.py | 23 +++ .../repositories/emp_chg_inst_repository.py | 127 ++++++++++++ .../src/services/master_mainte_service.py | 44 ++++- .../static/function/businessLogicScript.js | 40 +--- ecs/jskult-webapp/src/system_var/constants.py | 36 ++++ .../src/system_var/environment.py | 1 + .../src/templates/instEmpCsvDL.html | 181 ++++++++++-------- 12 files changed, 636 insertions(+), 130 deletions(-) create mode 100644 ecs/jskult-webapp/src/model/request/master_mainte_csvdl.py diff --git a/ecs/jskult-webapp/.env.example b/ecs/jskult-webapp/.env.example index 0630afe4..10844a21 100644 --- a/ecs/jskult-webapp/.env.example +++ b/ecs/jskult-webapp/.env.example @@ -10,6 +10,7 @@ COGNITO_CLIENT_SECRET=****************************** SESSION_TABLE_NAME=*********************** ##S3 BIO_ACCESS_LOG_BUCKET=******************* +MASTER_MAINTENANCE_BUCKET=mbj-newdwh2021-staging-jskult-master-maintenance #MySQL DB_HOST=************ DB_PORT=************ diff --git a/ecs/jskult-webapp/src/controller/master_mainte.py b/ecs/jskult-webapp/src/controller/master_mainte.py index c97d40eb..638f4595 100644 --- a/ecs/jskult-webapp/src/controller/master_mainte.py +++ b/ecs/jskult-webapp/src/controller/master_mainte.py @@ -1,9 +1,13 @@ +from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import HTMLResponse from starlette import status +from src.error.exceptions import DBException +import pandas as pd from src.depends.services import get_service +from src.logging.get_logger import get_logger from src.model.internal.session import UserSession from src.model.view.inst_emp_csv_download_view_model import \ InstEmpCsvDownloadViewModel @@ -19,9 +23,11 @@ from src.services.session_service import set_session from src.system_var import constants from src.templates import templates from src.model.request.master_mainte_csvup import MasterMainteCsvUpModel -from fastapi import APIRouter, File, Form, Request +from src.model.request.master_mainte_csvdl import MasterMainteCsvDlModel from io import TextIOWrapper, BytesIO +logger = get_logger('マスターメンテ') + router = APIRouter() router.route_class = AuthenticatedRoute @@ -133,7 +139,7 @@ async def inst_emp_csv_upload( # 画面表示用のモデル mainte_csv_up = master_mainte_service.prepare_mainte_csv_up_view( - TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read())), + TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read()), encoding='utf-8'), csv_upload_form.csv_file.filename, csv_upload_form) # セッション書き換え @@ -217,7 +223,9 @@ def inst_emp_csv_download_view( raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING) # 画面表示用のモデル - view_model = InstEmpCsvDownloadViewModel() + mainte_csv_dl = InstEmpCsvDownloadViewModel( + is_search=False + ) # セッション書き換え session.update( actions=[ @@ -230,7 +238,98 @@ def inst_emp_csv_download_view( 'instEmpCsvDL.html', { 'request': request, - 'view': view_model + 'mainte_csv_dl': mainte_csv_dl + }, + headers={'session_key': session.session_key} + ) + return templates_response + + +@router.post('/download', response_class=HTMLResponse) +async def inst_emp_csv_download( + request: Request, + csv_download_form: Optional[MasterMainteCsvDlModel] = Depends(MasterMainteCsvDlModel.as_form), + master_mainte_service: MasterMainteService = Depends(get_service(MasterMainteService)), + batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)) +): + session: UserSession = request.session + + # マスタメンテメニューへのアクセス権がない場合、ログアウトさせる + if session.master_mainte_flg != '1': + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) + + # バッチ処理中の場合、ログアウトさせる + if batch_status_service.is_batch_processing(): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, + detail=constants.LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE) + # dump処理中の場合、ログアウトさせる + if batch_status_service.is_dump_processing(): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING) + + search_result_df, _ = _search_emp_chg_inst_data(master_mainte_service, csv_download_form) + download_file_url = '' + if search_result_df.size > 0: + extract_df = _extract_output_df(search_result_df) + + # ファイル名に使用するタイムスタンプを初期化しておく + current_timestamp = datetime.now() + download_file_name = f'Result_{session.user_id}_{current_timestamp:%Y%m%d%H%M%S%f}.csv' + + # ファイルを書き出し(CSV) + local_file_path = _write_emp_chg_inst_data_to_file(master_mainte_service, extract_df, download_file_name) + + # ローカルファイルからS3にアップロードし、ダウンロード用URLを取得する + try: + master_mainte_service.upload_emp_chg_inst_data_file(local_file_path) + download_file_url = master_mainte_service.generate_download_file_url(local_file_path) + except Exception as e: + logger.exception(f'S3 アクセスエラー{e}') + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail={'error': 'aws_error', 'message': e.args} + ) + if csv_download_form.select_table == 'dummy': + result_msg = f'ダミーテーブルのデータ{search_result_df.size}件をCSVファイルに出力しました' + else: + result_msg = f'本番テーブルのデータ{search_result_df.size}件をCSVファイルに出力しました' + else: + result_msg = '該当データが存在しないためCSVファイルを出力しませんでした' + + # 画面表示用のモデル + mainte_csv_dl = InstEmpCsvDownloadViewModel( + is_search=True, + ta_cd=csv_download_form.ta_cd, + inst_cd=csv_download_form.inst_cd, + emp_cd=csv_download_form.emp_cd, + apply_date=csv_download_form.apply_date, + start_date_from=csv_download_form.start_date_from, + start_date_to=csv_download_form.start_date_to, + end_date_from=csv_download_form.end_date_from, + end_date_to=csv_download_form.end_date_to, + create_date_from=csv_download_form.create_date_from, + create_date_to=csv_download_form.create_date_to, + update_date_from=csv_download_form.update_date_from, + update_date_to=csv_download_form.update_date_to, + select_table=csv_download_form.select_table, + data_count=search_result_df.size, + download_file_url=download_file_url, + file_name=constants.MENTE_CSV_DOWNLOAD_FILE_NAME, + result_msg=result_msg + ) + + # セッション書き換え + session.update( + actions=[ + UserSession.last_access_time.set(UserSession.new_last_access_time()), + UserSession.record_expiration_time.set(UserSession.new_record_expiration_time()), + ] + ) + set_session(session) + templates_response = templates.TemplateResponse( + 'instEmpCsvDL.html', + { + 'request': request, + 'mainte_csv_dl': mainte_csv_dl }, headers={'session_key': session.session_key} ) @@ -275,3 +374,34 @@ def table_override_view( headers={'session_key': session.session_key} ) return templates_response + + +def _search_emp_chg_inst_data(master_mainte_service: MasterMainteService, + csv_download_form: MasterMainteCsvDlModel) -> pd.DataFrame: + try: + csv_download_form.unescape() + # 施設担当者データを検索 + search_result_df, query = master_mainte_service.search_download_emp_chg_inst_data(csv_download_form) + except DBException as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail={'error': 'db_error', 'message': e.args} + ) + + return search_result_df, query + + +def _extract_output_df(search_result_df: pd.DataFrame) -> pd.DataFrame: + return search_result_df[constants.MENTE_CSV_DOWNLOAD_EXTRACT_COLUMNS] + + +def _write_emp_chg_inst_data_to_file( + master_mainte_service: MasterMainteService, + df: pd.DataFrame, + download_file_name: str +) -> str: + logger.info('CSVファイルを出力する') + local_file_path = master_mainte_service.write_csv_file( + df, header=constants.MENTE_CSV_DOWNLOAD_HEADER, download_file_name=download_file_name) + + return local_file_path diff --git a/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py b/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py index c093fe0c..0d3017c1 100644 --- a/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py +++ b/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py @@ -203,6 +203,8 @@ class MasterMainteNewInstEmpCSVItem(MasterMainteCSVItem): bu_master_repository, emp_chginst_repository ) + # get_csv_value() indexerrorでキャッチするメソッドを追加する + self.inst_cd = self.csv_row[constants.CSV_NEW_INST_CD_COL_NO] self.inst_name = self.csv_row[constants.CSV_NEW_INST_NAME_COL_NO] self.ta_cd = self.csv_row[constants.CSV_NEW_TA_CD_COL_NO] @@ -324,6 +326,8 @@ class MasterMainteChangeInstEmpCSVItem(MasterMainteCSVItem): bu_master_repository, emp_chginst_repository ) + # self.bu_cd = get_csv_value(constants.CSV_CHANGE_BU_CD_COL_NO) ← IndexErrorでtry catch + self.bu_cd = self.csv_row[constants.CSV_CHANGE_BU_CD_COL_NO] self.bu_name = self.csv_row[constants.CSV_CHANGE_BU_NAME_COL_NO] self.org_cd = self.csv_row[constants.CSV_CHANGE_ORG_CD_COL_NO] diff --git a/ecs/jskult-webapp/src/model/request/master_mainte_csvdl.py b/ecs/jskult-webapp/src/model/request/master_mainte_csvdl.py new file mode 100644 index 00000000..293674e3 --- /dev/null +++ b/ecs/jskult-webapp/src/model/request/master_mainte_csvdl.py @@ -0,0 +1,169 @@ +from typing import Optional + +from fastapi import Form + +from src.util.sanitize import sanitize + +from src.model.request.request_base_model import RequestBaseModel +from src.util.string_util import is_not_empty + + +@sanitize +class MasterMainteCsvDlModel(RequestBaseModel): + ta_cd: Optional[str] + adapt_ta_cd: Optional[str] + inst_cd: Optional[str] + adapt_inst_cd: Optional[str] + emp_cd: Optional[str] + adapt_emp_cd: Optional[str] + apply_date: Optional[str] + adapt_apply_date: Optional[str] + start_date_from: Optional[str] + adapt_start_date_from: Optional[str] + start_date_to: Optional[str] + adapt_start_date_to: Optional[str] + end_date_from: Optional[str] + adapt_end_date_from: Optional[str] + end_date_to: Optional[str] + adapt_end_date_to: Optional[str] + select_table: Optional[str] + create_date_from: Optional[str] + adapt_create_date_from: Optional[str] + create_date_to: Optional[str] + adapt_create_date_to: Optional[str] + update_date_from: Optional[str] + adapt_update_date_from: Optional[str] + update_date_to: Optional[str] + adapt_update_date_to: Optional[str] + + @classmethod + def as_form( + cls, + ctrl_ta_cd: Optional[str] = Form(None), + ctrl_inst_cd: Optional[str] = Form(None), + ctrl_emp_cd: Optional[str] = Form(None), + ctrl_apply_date: Optional[str] = Form(None), + ctrl_start_date_from: Optional[str] = Form(None), + ctrl_start_date_to: Optional[str] = Form(None), + ctrl_end_date_from: Optional[str] = Form(None), + ctrl_end_date_to: Optional[str] = Form(None), + radio_select_table: Optional[str] = Form(None), + ctrl_create_date_from: Optional[str] = Form(None), + ctrl_create_date_to: Optional[str] = Form(None), + ctrl_update_date_from: Optional[str] = Form(None), + ctrl_update_date_to: Optional[str] = Form(None) + ): + return cls.__convert_request_param( + cls, + ctrl_ta_cd, + ctrl_inst_cd, + ctrl_emp_cd, + ctrl_apply_date, + ctrl_start_date_from, + ctrl_start_date_to, + ctrl_end_date_from, + ctrl_end_date_to, + radio_select_table, + ctrl_create_date_from, + ctrl_create_date_to, + ctrl_update_date_from, + ctrl_update_date_to + ) + + def __convert_request_param( + cls, + ctrl_ta_cd: str, + ctrl_inst_cd: str, + ctrl_emp_cd: str, + ctrl_apply_date: str, + ctrl_start_date_from: str, + ctrl_start_date_to: str, + ctrl_end_date_from: str, + ctrl_end_date_to: str, + radio_select_table: str, + ctrl_create_date_from: str, + ctrl_create_date_to: str, + ctrl_update_date_from: str, + ctrl_update_date_to: str + ): + ctrl_ta_cd = ctrl_ta_cd if is_not_empty(ctrl_ta_cd) else '' + ctrl_inst_cd = ctrl_inst_cd if is_not_empty(ctrl_inst_cd) else '' + ctrl_emp_cd = ctrl_emp_cd if is_not_empty(ctrl_emp_cd) else '' + + adapt_apply_date = '' + if is_not_empty(ctrl_apply_date): + adapt_apply_date = ctrl_apply_date.replace('/', '') + else: + ctrl_apply_date = '' + + adapt_start_date_from = '' + adapt_start_date_to = '' + if is_not_empty(ctrl_start_date_from): + adapt_start_date_from = ctrl_start_date_from.replace('/', '') + else: + ctrl_start_date_from = '' + if is_not_empty(ctrl_start_date_to): + adapt_start_date_to = ctrl_start_date_to.replace('/', '') + else: + ctrl_start_date_to = '' + + adapt_end_date_from = '' + adapt_end_date_to = '' + if is_not_empty(ctrl_end_date_from): + adapt_end_date_from = ctrl_end_date_from.replace('/', '') + else: + ctrl_end_date_from = '' + if is_not_empty(ctrl_end_date_to): + adapt_end_date_to = ctrl_end_date_to.replace('/', '') + else: + ctrl_end_date_to = '' + + adapt_create_date_from = '' + adapt_create_date_to = '' + if is_not_empty(ctrl_create_date_from): + adapt_create_date_from = ctrl_create_date_from.replace('/', '') + else: + ctrl_create_date_from = '' + if is_not_empty(ctrl_create_date_to): + adapt_create_date_to = ctrl_create_date_to.replace('/', '') + else: + ctrl_create_date_to = '' + + adapt_update_date_from = '' + adapt_update_date_to = '' + if is_not_empty(ctrl_update_date_from): + adapt_update_date_from = ctrl_update_date_from.replace('/', '') + else: + ctrl_update_date_from = '' + if is_not_empty(ctrl_update_date_to): + adapt_update_date_to = ctrl_update_date_to.replace('/', '') + else: + ctrl_update_date_to = '' + + return cls( + ta_cd=ctrl_ta_cd, + adapt_ta_cd=ctrl_ta_cd, + inst_cd=ctrl_inst_cd, + adapt_inst_cd=ctrl_inst_cd, + emp_cd=ctrl_emp_cd, + adapt_emp_cd=ctrl_emp_cd, + apply_date=ctrl_apply_date, + adapt_apply_date=adapt_apply_date, + start_date_from=ctrl_start_date_from, + adapt_start_date_from=adapt_start_date_from, + start_date_to=ctrl_start_date_to, + adapt_start_date_to=adapt_start_date_to, + select_table=radio_select_table, + end_date_from=ctrl_end_date_from, + adapt_end_date_from=adapt_end_date_from, + end_date_to=ctrl_end_date_to, + adapt_end_date_to=adapt_end_date_to, + create_date_from=ctrl_create_date_from, + adapt_create_date_from=adapt_create_date_from, + create_date_to=ctrl_create_date_to, + adapt_create_date_to=adapt_create_date_to, + update_date_from=ctrl_update_date_from, + adapt_update_date_from=adapt_update_date_from, + update_date_to=ctrl_update_date_to, + adapt_update_date_to=adapt_update_date_to + ) diff --git a/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py b/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py index 55f5a470..2f24bd8b 100644 --- a/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py +++ b/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py @@ -21,7 +21,7 @@ class MasterMainteCsvUpModel(RequestBaseModel): ctrl_csv_file: UploadFile = Form(None), ctrl_select_function: Optional[str] = Form(None), ctrl_select_table: Optional[str] = Form(None), - ctrl_json_upload_data: Optional[str] = Form(None), + ctrl_json_upload_data: Optional[str] = Form(None) ): return cls( csv_file=ctrl_csv_file, diff --git a/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py b/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py index 220294ba..e630615e 100644 --- a/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py +++ b/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py @@ -1,5 +1,28 @@ from pydantic import BaseModel +from typing import Optional +from src.util.string_util import is_not_empty class InstEmpCsvDownloadViewModel(BaseModel): subtitle: str = '施設担当者データCSVダウンロード' + is_search: Optional[bool] = False + ta_cd: Optional[str] = '' + inst_cd: Optional[str] = '' + emp_cd: Optional[str] = '' + apply_date: Optional[str] = '' + start_date_from: Optional[str] = '' + start_date_to: Optional[str] = '' + end_date_from: Optional[str] = '' + end_date_to: Optional[str] = '' + create_date_from: Optional[str] = '' + create_date_to: Optional[str] = '' + update_date_from: Optional[str] = '' + update_date_to: Optional[str] = '' + select_table: Optional[str] = '' + data_count: Optional[int] = 0 + result_msg: Optional[str] = '' + download_file_url: Optional[str] = '' + file_name: Optional[str] = '' + + def is_select_table_empty(self): + return not is_not_empty(self.select_table) diff --git a/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py b/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py index abcd93ea..4ef7b836 100644 --- a/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py +++ b/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py @@ -1,5 +1,9 @@ from src.repositories.base_repository import BaseRepository +from src.db.sql_condition import SQLCondition +from src.db import sql_condition as condition from src.model.db.master_mente_count import MasterMenteCountModel +from src.model.request.master_mainte_csvdl import MasterMainteCsvDlModel +from src.util.string_util import is_not_empty from src.logging.get_logger import get_logger logger = get_logger('従業員担当施設マスタ') @@ -153,3 +157,126 @@ class EmpChgInstRepository(BaseRepository): raise e finally: self._database.disconnect() + + FETCH_SQL = """\ + SELECT DISTINCT + eci.inst_cd AS inst_cd, + mi.inst_name AS inst_name, + eci.ta_cd AS ta_cd, + eci.emp_cd AS emp_cd, + CONCAT(emp.emp_name_family, " ", emp.emp_name_first) AS emp_name_full, + eci.bu_cd AS bu_cd, + bu.bu_name AS bu_name, + eci.start_date AS start_date, + eci.end_date AS end_date, + eci.creater AS creater, + eci.create_date AS create_date, + eci.updater AS updater, + eci.update_date AS update_date + FROM + {table_name} AS eci + LEFT JOIN mst_inst AS mi + ON eci.inst_cd = mi.inst_cd + LEFT JOIN emp + ON eci.emp_cd = emp.emp_cd + LEFT JOIN bu + ON eci.bu_cd = bu.bu_cd + WHERE + {where_clause} + """ + + def fetch_as_data_frame(self, table_name: str, parameter: MasterMainteCsvDlModel): + try: + self._database.connect() + logger.debug('DB参照実行') + where_clause = self.__build_condition(parameter) + query = self.FETCH_SQL.format(table_name=table_name, where_clause=where_clause) + logger.debug(f'SQL: {query}') + df = self._to_data_frame(query, parameter) + logger.debug(f'count= {len(df.index)}') + # ログ出力のため、クエリも返却 + return df, query + except Exception as e: + logger.exception(f"DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() + + def __build_condition(self, parameter: MasterMainteCsvDlModel): + where_clauses: list[SQLCondition] = [] + + # 領域コードが入力されていた場合 + if is_not_empty(parameter.ta_cd): + parameter.adapt_ta_cd = f'%{parameter.ta_cd}%' + where_clauses.append(SQLCondition('eci.ta_cd', condition.LIKE, 'adapt_ta_cd')) + + # 施設コードが入力されていた場合 + if is_not_empty(parameter.inst_cd): + parameter.adapt_inst_cd = f'%{parameter.inst_cd}%' + where_clauses.append(SQLCondition('eci.inst_cd', condition.LIKE, 'adapt_inst_cd')) + + # MUIDが入力されていた場合 + if is_not_empty(parameter.emp_cd): + parameter.adapt_emp_cd = f'%{parameter.emp_cd}%' + where_clauses.append(SQLCondition('eci.emp_cd', condition.LIKE, 'adapt_emp_cd')) + + # 適用期間内が入力されていた場合 + if is_not_empty(parameter.adapt_apply_date): + where_clauses.append(SQLCondition('eci.START_DATE', + condition.LE, + 'adapt_apply_date')) + where_clauses.append(SQLCondition('eci.END_DATE', + condition.GE, + 'adapt_apply_date')) + + # 適用開始日(FROM)が入力されていた場合 + if is_not_empty(parameter.adapt_start_date_from): + where_clauses.append(SQLCondition('eci.START_DATE', + condition.GE, + 'adapt_start_date_from')) + + # 適用開始日(TO)が入力されていた場合 + if is_not_empty(parameter.adapt_start_date_to): + where_clauses.append(SQLCondition('eci.START_DATE', + condition.LE, + 'adapt_start_date_to')) + + # 適用終了日(FROM)が入力されていた場合 + if is_not_empty(parameter.adapt_end_date_from): + where_clauses.append(SQLCondition('eci.END_DATE', + condition.GE, + 'adapt_end_date_from')) + + # 適用終了日(TO)が入力されていた場合 + if is_not_empty(parameter.adapt_end_date_to): + where_clauses.append(SQLCondition('eci.END_DATE', + condition.LE, + 'adapt_end_date_to')) + + # データ作成日(FROM)が入力されていた場合 + if is_not_empty(parameter.adapt_create_date_from): + where_clauses.append(SQLCondition('eci.CREATE_DATE', + condition.GE, + 'adapt_create_date_from')) + + # データ作成日(TO)が入力されていた場合 + if is_not_empty(parameter.adapt_create_date_to): + where_clauses.append(SQLCondition('eci.CREATE_DATE', + condition.LE, + 'adapt_create_date_to')) + + # データ作成日(FROM)が入力されていた場合 + if is_not_empty(parameter.adapt_update_date_from): + where_clauses.append(SQLCondition('eci.UPDATE_DATE', + condition.GE, + 'adapt_update_date_from')) + + # データ作成日(TO)が入力されていた場合 + if is_not_empty(parameter.adapt_update_date_to): + where_clauses.append(SQLCondition('eci.UPDATE_DATE', + condition.LE, + 'adapt_update_date_to')) + + where_clauses_str = ' AND '.join([condition.apply() for condition in where_clauses]) + logger.debug(f'条件設定終了:{where_clauses_str}') + return where_clauses_str diff --git a/ecs/jskult-webapp/src/services/master_mainte_service.py b/ecs/jskult-webapp/src/services/master_mainte_service.py index 3d0d24f9..8d37d182 100644 --- a/ecs/jskult-webapp/src/services/master_mainte_service.py +++ b/ecs/jskult-webapp/src/services/master_mainte_service.py @@ -1,7 +1,12 @@ +import os import json import html + +import pandas as pd + from io import TextIOWrapper from src.aws.aws_api_client import AWSAPIClient +from src.aws.s3 import S3Client from src.repositories.base_repository import BaseRepository from src.services.base_service import BaseService from src.model.internal.master_mainte_csv import MasterMainteCSVItems @@ -9,6 +14,7 @@ from src.model.internal.master_mainte_emp_chg import MasterMainteNewEmpChg from src.model.internal.master_mainte_emp_chg import MasterMainteChangeEmpChg from src.model.view.inst_emp_csv_upload_view_model import InstEmpCsvUploadViewModel from src.model.request.master_mainte_csvup import MasterMainteCsvUpModel +from src.model.request.master_mainte_csvdl import MasterMainteCsvDlModel from src.logging.get_logger import get_logger from src.model.view.mainte_csv_upload_model import CsvUploadModel from src.model.view.mainte_csv_error_model import CsvErrorModel @@ -16,7 +22,7 @@ from src.repositories.mst_inst_repository import MstInstRepository from src.repositories.bu_master_cd_repository import BuMasterRepository from src.repositories.emp_master_repository import EmpMasterRepository from src.repositories.emp_chg_inst_repository import EmpChgInstRepository -from src.system_var import constants +from src.system_var import constants, environment logger = get_logger('マスターメンテ') @@ -29,10 +35,15 @@ class MasterMainteService(BaseService): 'emp_chginst_repository': EmpChgInstRepository, } + CLIENTS = { + 's3_client': S3Client + } + mst_inst_repository: MstInstRepository emp_master_repository: EmpMasterRepository bu_master_repository: BuMasterRepository emp_chginst_repository: EmpChgInstRepository + s3_client: S3Client def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None: super().__init__(repositories, clients) @@ -40,6 +51,7 @@ class MasterMainteService(BaseService): self.emp_master_repository = repositories['emp_master_repository'] self.bu_master_repository = repositories['bu_master_repository'] self.emp_chginst_repository = repositories['emp_chginst_repository'] + self.s3_client = clients['s3_client'] def prepare_mainte_csv_up_view(self, file: TextIOWrapper, @@ -125,6 +137,36 @@ class MasterMainteService(BaseService): ) return mainte_csv_up + def search_download_emp_chg_inst_data(self, csv_download_form: MasterMainteCsvDlModel): + (table_name, _) = self.__target_table(csv_download_form.select_table) + search_result_df, query = self.emp_chginst_repository.fetch_as_data_frame(table_name, csv_download_form) + return search_result_df, query + + def write_csv_file(self, data_frame: pd.DataFrame, header: list[str], download_file_name: str): + # csvに書き込み + output_file_path = os.path.join(constants.MENTE_CSV_TEMPORARY_FILE_DIR_PATH, download_file_name) + # 横長のDataFrameとするため、ヘッダーの加工処理 + header_data = {} + for df_column, header_column in zip(data_frame.columns, header): + header_data[df_column] = header_column + + 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) + + return output_file_path + + def upload_emp_chg_inst_data_file(self, local_file_path: str) -> None: + bucket_name = environment.MASTER_MAINTENANCE_BUCKET + file_key = f'data/{os.path.basename(local_file_path)}' + self.s3_client.upload_file(local_file_path, bucket_name, file_key) + + def generate_download_file_url(self, local_file_path: str) -> str: + bucket_name = environment.MASTER_MAINTENANCE_BUCKET + file_key = f'data/{os.path.basename(local_file_path)}' + return self.s3_client.generate_presigned_url(bucket_name, file_key, constants.MENTE_CSV_DOWNLOAD_FILE_NAME) + def __target_table(self, select_table: str): if select_table == 'dummy': table_name = 'src05.emp_chg_inst_wrk' diff --git a/ecs/jskult-webapp/src/static/function/businessLogicScript.js b/ecs/jskult-webapp/src/static/function/businessLogicScript.js index 8e711fbe..6b860ca3 100644 --- a/ecs/jskult-webapp/src/static/function/businessLogicScript.js +++ b/ecs/jskult-webapp/src/static/function/businessLogicScript.js @@ -226,21 +226,7 @@ function checkNumberOnlyForm($this) // メニューへボタンの関数 // 機能概要:マスターメンテメニュー画面に遷移する function backToMainteMenu(){ - location.href = "/masterMainte/masterMainteMenu.php"; -} - -// クリアボタンの関数 -// 利用条件1:form名がsearch -// 引数にはクリアしたいinputの数 -// 上から順番にクリアされる -function clrMainte(elementNum){ - for (var i = 1; i <= elementNum; i++) { - // document.form名[要素名].value="いれたい値"; - var elementsName = "textbox_" + i; - document.search[elementsName].value = ""; - } - // ボタンの非活性化 - formBtDisabled(elementNum); + location.href = "/menu/"; } // 確認ダイアログ @@ -249,30 +235,6 @@ function confirmDialog(strMesssage) { return result; } -// 検索ボタンの活性非活性関数 -// 利用条件1:form名がsearch -// 利用条件2:textbox名がtextbox_数字(1から連番) -// 引数にはテキストボックスの数 -function formBtDisabled(elementNum){ - var validFlg = false; - for (var i = 1; i <= elementNum; i++) { - var elementsName = "textbox_" + i; - if(document.search[elementsName].value.length > 0){ - validFlg = true; - break; - } - } - - if (validFlg == true) { - $('#csvDL').removeAttr('disabled'); - $('#clear').removeAttr('disabled'); - } - else { - $('#csvDL').attr('disabled', 'disabled'); - $('#clear').attr('disabled', 'disabled'); - } -} - function formInsertBtDisabled(){ var validFlg = false; if(document.getElementById("excelFile").value === ""){ diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 54e4c575..f94d65de 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -219,3 +219,39 @@ CSV_CHANGE_COL_COUNT = 14 # 施設担当者変更登録CSV # CSVアップロードテーブル名(マスターメンテ) CSV_REAL_TABLE_NAME = '本番テーブル' CSV_CHANGE_TABLE_NAME = 'ダミーテーブル' + +MENTE_CSV_TEMPORARY_FILE_DIR_PATH = path.join(path.curdir, 'src', 'data') + +MENTE_CSV_DOWNLOAD_EXTRACT_COLUMNS = [ + 'inst_cd', + 'inst_name', + 'ta_cd', + 'emp_cd', + 'emp_name_full', + 'bu_cd', + 'bu_name', + 'start_date', + 'end_date', + 'creater', + 'create_date', + 'updater', + 'update_date' +] + +MENTE_CSV_DOWNLOAD_HEADER = [ + '施設コード', + '施設名', + '領域コード', + 'MUID', + '担当者名', + 'ビジネスユニットコード', + 'ビジネスユニット名', + '適用開始日', + '適用終了日', + '作成者', + '作成日', + '更新者', + '更新日' +] + +MENTE_CSV_DOWNLOAD_FILE_NAME = 'instEmpData.csv' diff --git a/ecs/jskult-webapp/src/system_var/environment.py b/ecs/jskult-webapp/src/system_var/environment.py index c5bf66ef..bbb40223 100644 --- a/ecs/jskult-webapp/src/system_var/environment.py +++ b/ecs/jskult-webapp/src/system_var/environment.py @@ -11,6 +11,7 @@ COGNITO_CLIENT_SECRET = os.environ['COGNITO_CLIENT_SECRET'] AWS_REGION = os.environ['AWS_REGION'] SESSION_TABLE_NAME = os.environ['SESSION_TABLE_NAME'] BIO_ACCESS_LOG_BUCKET = os.environ['BIO_ACCESS_LOG_BUCKET'] +MASTER_MAINTENANCE_BUCKET = os.environ['MASTER_MAINTENANCE_BUCKET'] DB_HOST = os.environ['DB_HOST'] DB_PORT = int(os.environ['DB_PORT']) diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html index 1209f8e2..9d0b69d8 100644 --- a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html +++ b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html @@ -4,26 +4,31 @@ {% with subtitle = mainte_csv_dl.subtitle %} {% include '_header.html' %} {% endwith %} - <!-- <?php echo $instEmpCsvDL ?> --> - - - + + -

施設担当者データCSVダウンロード

- - + +
施設担当者データCSVダウンロード

- -
+ - + - + - + - + - + - + - + - + - +
領域コード: - + 施設コード: - + MUID: - +
適用期間内: - + 適用開始日: - + ~ - + 適用終了日: - + ~ - +
対象テーブル: - データ作成日: - + ~ - + データ更新日: - + ~ - +
- - + +
-

- +

+ {% if mainte_csv_dl.is_search %} + {% if mainte_csv_dl.data_count == 0 %} +

{{mainte_csv_dl.result_msg}}
+ {% else %} +
{{mainte_csv_dl.result_msg}}
+ {% endif %} + {% endif %}

- - - -