diff --git a/ecs/jskult-webapp/src/controller/master_mainte.py b/ecs/jskult-webapp/src/controller/master_mainte.py index f251f57b..3fe61846 100644 --- a/ecs/jskult-webapp/src/controller/master_mainte.py +++ b/ecs/jskult-webapp/src/controller/master_mainte.py @@ -1,14 +1,9 @@ from io import BytesIO, TextIOWrapper -from datetime import datetime from typing import Optional -import pandas as pd from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import HTMLResponse from starlette import status -from src.error.exceptions import DBException - - from src.depends.services import get_service from src.logging.get_logger import get_logger from src.model.internal.session import UserSession @@ -269,34 +264,12 @@ async def inst_emp_csv_download( 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) + search_result_df = master_mainte_service.search_emp_chg_inst_data(csv_download_form) - # ファイル名に使用するタイムスタンプを初期化しておく - 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ファイルを出力しませんでした' + (result_msg, download_file_url) = master_mainte_service.upload_emp_chg_inst_data_file( + search_result_df, + session.user_id, + csv_download_form.select_table) # 画面表示用のモデル mainte_csv_dl = InstEmpCsvDownloadViewModel( @@ -400,7 +373,7 @@ def table_override_result_view( raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING) # 画面表示用のモデル - table_override = master_mainte_service.prepare_mainte_table_override_view() + table_override = master_mainte_service.copy_data_real_to_dummy() # セッション書き換え session.update( @@ -419,34 +392,3 @@ def table_override_result_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/view/inst_emp_csv_download_view_model.py b/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py index e630615e..f35aa7cb 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 @@ -26,3 +26,6 @@ class InstEmpCsvDownloadViewModel(BaseModel): def is_select_table_empty(self): return not is_not_empty(self.select_table) + + def is_download_file_url_empty(self): + return not is_not_empty(self.download_file_url) 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 562ad642..04e8b0d7 100644 --- a/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py +++ b/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py @@ -195,7 +195,7 @@ class EmpChgInstRepository(BaseRepository): df = self._to_data_frame(query, parameter) logger.debug(f'count= {len(df.index)}') # ログ出力のため、クエリも返却 - return df, query + return df except Exception as e: logger.exception(f"DB Error : Exception={e.args}") raise e diff --git a/ecs/jskult-webapp/src/services/master_mainte_service.py b/ecs/jskult-webapp/src/services/master_mainte_service.py index 36015fe2..54849b98 100644 --- a/ecs/jskult-webapp/src/services/master_mainte_service.py +++ b/ecs/jskult-webapp/src/services/master_mainte_service.py @@ -4,9 +4,13 @@ import html import pandas as pd +from fastapi import HTTPException from io import TextIOWrapper from src.aws.aws_api_client import AWSAPIClient from src.aws.s3 import S3Client +from src.error.exceptions import DBException +from starlette import status +from datetime import datetime from src.services.base_service import BaseService from src.system_var import constants, environment from src.repositories.base_repository import BaseRepository @@ -63,7 +67,7 @@ class MasterMainteService(BaseService): if csv_upload_form.select_table != 'dummy' and csv_upload_form.select_table != 'real': raise Exception(f'登録テーブルの選択値が不正です: {csv_upload_form.select_table}') - (table_name, _) = self.__target_table(csv_upload_form.select_table) + (table_name, _) = self.__choose_target_table(csv_upload_form.select_table) csv_items = MasterMainteCSVItems( file, @@ -105,7 +109,7 @@ class MasterMainteService(BaseService): user_name: str, csv_upload_form: MasterMainteCsvUpModel) -> InstEmpCsvUploadViewModel: - (table_name, selected_table_msg) = self.__target_table(csv_upload_form.select_table) + (table_name, selected_table_msg) = self.__choose_target_table(csv_upload_form.select_table) csv_data_list = json.loads(html.unescape(csv_upload_form.unescape().json_upload_data)) @@ -138,7 +142,7 @@ class MasterMainteService(BaseService): ) return mainte_csv_up - def prepare_mainte_table_override_view(self) -> TableOverrideViewModel: + def copy_data_real_to_dummy(self) -> TableOverrideViewModel: try: self.emp_chginst_repository.connect() self.emp_chginst_repository.begin() @@ -151,15 +155,29 @@ class MasterMainteService(BaseService): finally: self.emp_chginst_repository.disconnect() + # コピー完了をマークして画面に返却 table_override = TableOverrideViewModel( is_override=True ) return table_override + def search_emp_chg_inst_data(self, csv_download_form: MasterMainteCsvDlModel) -> pd.DataFrame: + try: + csv_download_form.unescape() + # 施設担当者データを検索 + search_result_df = self.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 + 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 + (table_name, _) = self.__choose_target_table(csv_download_form.select_table) + search_result_df = self.emp_chginst_repository.fetch_as_data_frame(table_name, csv_download_form) + return search_result_df def write_csv_file(self, data_frame: pd.DataFrame, header: list[str], download_file_name: str): # csvに書き込み @@ -176,19 +194,52 @@ class MasterMainteService(BaseService): 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) - # アップロード後、ローカルからは削除する - self.delete_local_file(local_file_path) + def upload_emp_chg_inst_data_file(self, df: pd.DataFrame, user_id: str, select_table: str) -> tuple[str, str]: + if df.size == 0: + return '該当データが存在しないためCSVファイルを出力しませんでした', '' + + # ファイル名に使用するタイムスタンプを初期化しておく + current_timestamp = datetime.now() + download_file_name = f'Result_{user_id}_{current_timestamp:%Y%m%d%H%M%S%f}.csv' + + # ファイルを書き出し(CSV) + local_file_path = self.__write_emp_chg_inst_data_to_file(df, download_file_name) + + # ローカルファイルからS3にアップロードし、ダウンロード用URLを取得する + download_file_url = '' + try: + 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) + # アップロード後、ローカルからは削除する + self.delete_local_file(local_file_path) + download_file_url = self.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 select_table == 'dummy': + result_msg = f'ダミーテーブルのデータ{df.size}件をCSVファイルに出力しました' + else: + result_msg = f'本番テーブルのデータ{df.size}件をCSVファイルに出力しました' + + return result_msg, download_file_url 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): + def __write_emp_chg_inst_data_to_file(self, df: pd.DataFrame, download_file_name: str) -> str: + logger.info('CSVファイルを出力する') + local_file_path = self.write_csv_file( + df, header=constants.MENTE_CSV_DOWNLOAD_HEADER, download_file_name=download_file_name) + + return local_file_path + + def __choose_target_table(self, select_table: str): if select_table == 'dummy': table_name = 'src05.emp_chg_inst_wrk' selected_table_msg = constants.CSV_CHANGE_TABLE_NAME diff --git a/ecs/jskult-webapp/src/static/function/businessLogicScript.js b/ecs/jskult-webapp/src/static/function/businessLogicScript.js index 6311df44..be1c4498 100644 --- a/ecs/jskult-webapp/src/static/function/businessLogicScript.js +++ b/ecs/jskult-webapp/src/static/function/businessLogicScript.js @@ -176,69 +176,68 @@ function allOn(){ // 条件:チェックボックスのクラス名に"selectedページ数"というのがついていること // 条件:ボタンにクラス名 send がついていること function allOff(){ - $(".selected").prop("checked", false); - $(".send").prop('disabled',true); + $(".selected").prop("checked", false); + $(".send").prop('disabled',true); } // 検索結果のところのボタンをチェックが1個でも付いたら押せるようにして、チェックがなければ押せないようにする関数 // 条件:チェックボックスのクラス名に"selected"というのがついていること // 条件:ボタンにクラス名 send がついていること function resultBtDisablead(){ - var cnt1 = $('.checkNum input:checkbox:checked').length; - console.log(cnt1); + var cnt1 = $('.checkNum input:checkbox:checked').length; + console.log(cnt1); if(cnt1 == 0) { $(".send").prop('disabled',true); } else { - $(".send").prop('disabled',false); + $(".send").prop('disabled',false); } } // 数字-以外を許さない入力チェック function checkNumberForm($this) { - var str=$this.value; - while(str.match(/[^\d\-]/)) - { - str=str.replace(/[^\d\-]/,""); - } - $this.value=str; + var str=$this.value; + while(str.match(/[^\d\-]/)) + { + str=str.replace(/[^\d\-]/,""); + } + $this.value=str; } // 数字以外を許さない入力チェック function checkNumberOnlyForm($this) { - var str=$this.value; - while(str.match(/[^\d]/)) - { - str=str.replace(/[^\d]/,""); - } - $this.value=str; + var str=$this.value; + while(str.match(/[^\d]/)) + { + str=str.replace(/[^\d]/,""); + } + $this.value=str; } // メニューへボタンの関数 // 機能概要:マスターメンテメニュー画面に遷移する function backToMainteMenu(){ - location.href = "/menu/"; + location.href = "/menu/"; } // 確認ダイアログ function confirmDialog(strMesssage) { - var result = confirm(strMesssage); - return result; + var result = confirm(strMesssage); + return result; } function formInsertBtDisabled(){ - var validFlg = false; - if(document.getElementById("csvFile").value === ""){ - validFlg = true; - } + var validFlg = false; + if(document.getElementById("csvFile").value === ""){ + validFlg = true; + } - if (validFlg == true) { - document.getElementById("confirm").disabled = true; - } - else { - document.getElementById("confirm").disabled = false; - } + if (validFlg == true) { + document.getElementById("confirm").disabled = true; + } + else { + document.getElementById("confirm").disabled = false; + } } - diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html index 9d0b69d8..e52de75a 100644 --- a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html +++ b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html @@ -15,7 +15,7 @@ // DatePickerを有効化 enableDatePicker(); // CSV自動ダウンロード処理 -{% if mainte_csv_dl.is_search and mainte_csv_dl.data_count > 0 %} +{% if mainte_csv_dl.is_search and mainte_csv_dl.data_count > 0 and mainte_csv_dl.is_download_file_url_empty == False %} var link_tag = document.createElement("a"); link_tag.Target="_blank"; link_tag.id = "download_url_link"; @@ -46,7 +46,7 @@ - +
施設担当者データCSVダウンロード
diff --git a/ecs/jskult-webapp/src/templates/tableOverride.html b/ecs/jskult-webapp/src/templates/tableOverride.html index 92648fd5..08a62407 100644 --- a/ecs/jskult-webapp/src/templates/tableOverride.html +++ b/ecs/jskult-webapp/src/templates/tableOverride.html @@ -25,7 +25,7 @@ - +
テーブル上書きコピー
@@ -43,7 +43,7 @@
- +