diff --git a/ecs/jskult-webapp/src/controller/master_mainte.py b/ecs/jskult-webapp/src/controller/master_mainte.py index ea972ad6..beb17f53 100644 --- a/ecs/jskult-webapp/src/controller/master_mainte.py +++ b/ecs/jskult-webapp/src/controller/master_mainte.py @@ -1,3 +1,4 @@ +from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import HTMLResponse from starlette import status @@ -13,9 +14,13 @@ from src.model.view.master_mainte_menu_view_model import \ from src.model.view.table_override_view_model import TableOverrideViewModel from src.router.session_router import AuthenticatedRoute from src.services.batch_status_service import BatchStatusService +from src.services.master_mainte_service import MasterMainteService 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 io import TextIOWrapper, BytesIO router = APIRouter() router.route_class = AuthenticatedRoute @@ -85,7 +90,14 @@ def inst_emp_csv_upload_view( raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING) # 画面表示用のモデル - view_model = InstEmpCsvUploadViewModel() + mainte_csv_up = InstEmpCsvUploadViewModel( + # is_verified=False, + # select_function="", + # select_table="", + # new_inst_emp="", + # dialog_msg="", + # error_list=[] + ) # セッション書き換え session.update( actions=[ @@ -98,14 +110,101 @@ def inst_emp_csv_upload_view( 'instEmpCsvUL.html', { 'request': request, - 'view': view_model + 'mainte_csv_up': mainte_csv_up }, headers={'session_key': session.session_key} ) return templates_response -@router.get('/instEmpCsvDL', response_class=HTMLResponse) +@router.post('/instEmpCsvUL', response_class=HTMLResponse) +async def inst_emp_csv_upload( + request: Request, + csv_upload_form: Optional[MasterMainteCsvUpModel] = Depends(MasterMainteCsvUpModel.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) + + # 画面表示用のモデル + mainte_csv_up = master_mainte_service.prepare_mainte_csv_up_view( + TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read())), + csv_upload_form.csv_file.filename, + csv_upload_form) + # セッション書き換え + 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( + 'instEmpCsvUL.html', + { + 'request': request, + 'mainte_csv_up': mainte_csv_up + }, + headers={'session_key': session.session_key} + ) + return templates_response + + +@router.post('/newInst', response_class=HTMLResponse) +def new_inst_result_view( + request: Request, + csv_upload_form: Optional[MasterMainteCsvUpModel] = Depends(MasterMainteCsvUpModel.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) + + # 画面表示用のモデル + mainte_csv_up = master_mainte_service.prepare_mainte_new_inst_view(session.user_id, csv_upload_form) + # セッション書き換え + 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( + 'instEmpCsvUL.html', + { + 'request': request, + 'mainte_csv_up': mainte_csv_up + }, + headers={'session_key': session.session_key} + ) + return templates_response + + +@ router.get('/instEmpCsvDL', response_class=HTMLResponse) def inst_emp_csv_download_view( request: Request, batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)) diff --git a/ecs/jskult-webapp/src/model/db/master_mente_count.py b/ecs/jskult-webapp/src/model/db/master_mente_count.py new file mode 100644 index 00000000..a3837819 --- /dev/null +++ b/ecs/jskult-webapp/src/model/db/master_mente_count.py @@ -0,0 +1,9 @@ +from typing import Optional + +from src.model.db.base_db_model import BaseDBModel +from src.util.sanitize import sanitize + + +@sanitize +class MasterMenteCountModel(BaseDBModel): + count: Optional[int] diff --git a/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py b/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py new file mode 100644 index 00000000..0edf92c8 --- /dev/null +++ b/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py @@ -0,0 +1,477 @@ +import csv +from io import TextIOWrapper +from abc import ABCMeta, abstractmethod +from src.system_var import constants +from src.repositories.mente_exist_inst_cd_repository import MenteExistInstCdRepository +from src.repositories.mente_exist_bu_cd_repository import MenteExistBuCdRepository +from src.repositories.mente_exist_emp_cd_repository import MenteExistEmpCdRepository +from src.repositories.mente_exist_dummy_data_repository import MenteExistDummyDataRepository +from src.repositories.mente_exist_real_data_repository import MenteExistRealDataRepository +from src.repositories.mente_exist_emp_chg_inst_repository import MenteExistEmpChgInstRepository +from src.model.request.master_mainte_csvup import MasterMainteCsvUpModel + + +class MasterMainteCSVItem(metaclass=ABCMeta): + + select_table: str + line_num: str + csv_row: list[str] # dictで持つかどうかは要検討 + inst_cd: str + ta_cd: str + emp_cd: str + inst_cd_repository: MenteExistInstCdRepository + emp_cd_repository: MenteExistEmpCdRepository + bu_cd_repository: MenteExistBuCdRepository + dummy_data_repository: MenteExistDummyDataRepository + real_data_repository: MenteExistRealDataRepository + emp_chg_inst_repository: MenteExistEmpChgInstRepository + + def __init__( + self, + csv_row: list[str], + select_table: str, + line_num: str, + inst_cd_repository: MenteExistInstCdRepository, + emp_cd_repository: MenteExistEmpCdRepository, + bu_cd_repository: MenteExistBuCdRepository, + dummy_data_repository: MenteExistDummyDataRepository, + real_data_repository: MenteExistRealDataRepository, + emp_chg_inst_repository: MenteExistEmpChgInstRepository + ): + self.select_table = select_table # ダミー or 本番 + self.csv_row = csv_row # CSVの1行 + self.line_num = line_num # CSVの行数 + self.inst_cd_repository = inst_cd_repository + self.emp_cd_repository = emp_cd_repository + self.bu_cd_repository = bu_cd_repository + self.dummy_data_repository = dummy_data_repository + self.real_data_repository = real_data_repository + self.emp_chg_inst_repository = emp_chg_inst_repository + + def validate(self) -> list[list[str]]: + """ + 項目のバリデーションを行うテンプレートメソッド\n + 各チェックロジックはサブクラスで実装する + エラーが有る場合、[行数、項目名: エラー内容]のリストを返す + """ + error_list = [] + # 必須チェック 及び コメントエラーチェック + error_list.extend(self.check_require()) + # 施設コード存在チェック + error_list.extend(self.check_inst_cd_exists()) + # MUID存在チェック + error_list.extend(self.check_emp_cd_exists()) + # BuCd存在チェック + error_list.extend(self.check_bu_cd_exists()) + # 適用開始日 < 適用終了日、実在日チェック + # error_list.extend(self.check_existing_date()) + # 項目数チェック + error_list.extend(self.check_item_count()) + # データ存在チェック + error_list.extend(self.check_data_exists()) + + # エラーのないリストを省いて返す + error_list = [error for error in error_list if len(error) != 0] + return error_list + + # protected? + def check_csv_item_count(self, item_count: int) -> list[str]: + error_list = [] + + for col_num, row in enumerate(self.csv_row, start=1): + if col_num > item_count and row is not None and len(row) > 0: + error_list.append([self.line_num, '', constants.CSV_UP_ITEM_CNT_ERR, 'の項目数が一致しません。項目数を確認してください。']) + break + return error_list + + def emp_chg_inst_count(self, start_date: str): + table_name = 'src05.emp_chg_inst_wrk' if self.select_table == 'dummy' else 'src05.emp_chg_inst' + # pythonは子クラスのメンバも親から呼べる? + return self.emp_chg_inst_repository.fetch_count(self.inst_cd, self.ta_cd, start_date, table_name) + + def is_error_emp_cd(self, start_date: str) -> bool: + if start_date is None or len(start_date) == 0: + return False + if self.emp_cd_repository.fetch_count(self.emp_cd, start_date, start_date) == 0: + return True + return False + + @abstractmethod + def csv_row_data(self) -> dict: + pass + ... + + @abstractmethod + def check_require(self) -> list[str]: + """必須チェック""" + pass + ... + + def check_inst_cd_exists(self) -> list[str]: + error_list = [] + + inst_cd_count = self.inst_cd_repository.fetch_count(self.inst_cd) + if inst_cd_count == 0: + # 親クラスに持った方がいいので即値指定 + error_list.append([self.line_num, '施設コード', constants.CSV_UP_NOT_EXIST_INST_CD_ERR, '']) + return error_list + + @abstractmethod + def check_emp_cd_exists(self) -> list[str]: + """MUID存在チェック""" + pass + + def check_bu_cd_exists(self) -> list[str]: + """BuCd存在チェック""" + error_list = [] + + bu_cd_count = self.bu_cd_repository.fetch_count(self.bu_cd) + if bu_cd_count == 0: + # 親クラスに持った方がいいので即値指定 + error_list.append([self.line_num, 'ビジネスユニットコード', constants.CSV_UP_NOT_EXIST_BU_CD_ERR, '']) + return error_list + + @abstractmethod + def check_existing_date(self) -> list[str]: + """適用開始日 < 適用終了日、実在日チェック""" + pass + + @abstractmethod + def check_item_count(self) -> list[str]: + """項目数チェック""" + pass + ... + + @abstractmethod + def check_data_exists(self) -> list[str]: + """データ存在チェック""" + pass + + +class MasterMainteNewInstEmpCSVItem(MasterMainteCSVItem): + """新規施設担当者登録CSV""" + # inst_cd: str # a + inst_name: str # b + # ta_cd: str # c + # emp_cd: str # d + emp_name_family: str # e + emp_name_first: str # f + bu_cd: str # g + start_date: str # h + end_date: str # i + + def __init__( + self, + csv_row: list[str], + select_table: str, + line_num: str, + inst_cd_repository: MenteExistInstCdRepository, + emp_cd_repository: MenteExistEmpCdRepository, + bu_cd_repository: MenteExistBuCdRepository, + dummy_data_repository: MenteExistDummyDataRepository, + real_data_repository: MenteExistRealDataRepository, + emp_chg_inst_repository: MenteExistEmpChgInstRepository + ): + super().__init__( + csv_row, + select_table, + line_num, + inst_cd_repository, + emp_cd_repository, + bu_cd_repository, + dummy_data_repository, + real_data_repository, + emp_chg_inst_repository + ) + self.inst_cd = self.csv_row[constants.CSV_NEW_INST_CD_COL_NO] # a + self.inst_name = self.csv_row[constants.CSV_NEW_INST_NAME_COL_NO] # b + self.ta_cd = self.csv_row[constants.CSV_NEW_TA_CD_COL_NO] # c + self.emp_cd = self.csv_row[constants.CSV_NEW_EMP_CD_COL_NO] # d + self.emp_name_family = self.csv_row[constants.CSV_NEW_EMP_NAME_FAMILY_COL_NO] # e + self.emp_name_first = self.csv_row[constants.CSV_NEW_EMP_NAME_FIRST_COL_NO] # f + self.bu_cd = self.csv_row[constants.CSV_NEW_BU_CD_COL_NO] # g + self.start_date = self.csv_row[constants.CSV_NEW_START_DATE] # h + self.end_date = self.csv_row[constants.CSV_NEW_END_DATE] # i + + def csv_row_data(self) -> dict: + return {constants.NEW_INST_EMP_CSV_MAP[i]: self.csv_row[i] for i in range(len(self.csv_row))} + + def check_require(self) -> list[str]: + error_list = [] + if len(self.inst_cd) == 0: + error_list.append([self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_INST_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) # エラーコードを入れないと、出力制御が難しい。 + # メッセージの一部を配列に混ぜるかどうか検討 + if len(self.ta_cd) == 0: + error_list.append( + [self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_TA_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + + if len(self.emp_cd) == 0: + error_list.append( + [self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_EMP_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + + if len(self.bu_cd) == 0: + error_list.append( + [self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_BU_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + + if len(self.start_date) == 0: + error_list.append( + [self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_START_DATE], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + + if len(self.end_date) == 0: + error_list.append( + [self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_END_DATE], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + + return error_list + + def check_emp_cd_exists(self) -> list[str]: + error_list = [] + if self.start_date is None or len(self.start_date) == 0: + return error_list + + if super().is_error_emp_cd(self.start_date) is True: + error_list.append([self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_EMP_CD_COL_NO], + constants.CSV_UP_NOT_EXIST_EMP_CD_ERR, '']) + + return error_list + + def check_item_count(self) -> list[str]: + return super().check_csv_item_count(constants.CSV_NEW_COL_COUNT) + + def check_data_exists(self) -> list[str]: + error_list = [] + if super().emp_chg_inst_count(self.start_date) > 0: + error_list.append([self.line_num, '', constants.CSV_UP_NEW_DATA_DUP_ERR, '']) + + return error_list + + def check_existing_date(self) -> list[str]: + return [] + + +class MasterMainteChangeInstEmpCSVItem(MasterMainteCSVItem): + """施設担当者変更登録CSV""" + bu_cd: str # a + bu_name: str # b + org_cd: str # c + org_short_name: str # d + # inst_cd: str # e + inst_name: str # f + # ta_cd: str # g + explain: str # h + # emp_cd: str # i + emp_full_name: str # j + inst_emp_start_date: str # k + inst_emp_end_date: str # l + change_end_date: str # m + comment: str # n + + def __init__( + self, + csv_row: list[str], + select_table: str, + line_num: str, + inst_cd_repository: MenteExistInstCdRepository, + emp_cd_repository: MenteExistEmpCdRepository, + bu_cd_repository: MenteExistBuCdRepository, + dummy_data_repository: MenteExistDummyDataRepository, + real_data_repository: MenteExistRealDataRepository, + emp_chg_inst_repository: MenteExistEmpChgInstRepository + ): + super().__init__( + csv_row, + select_table, + line_num, + inst_cd_repository, + emp_cd_repository, + bu_cd_repository, + dummy_data_repository, + real_data_repository, + emp_chg_inst_repository + ) + + 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] + self.org_short_name = self.csv_row[constants.CSV_CHANGE_ORG_SHORT_NAME_COL_NO] + self.inst_cd = self.csv_row[constants.CSV_CHANGE_INST_CD_COL_NO] + self.inst_name = self.csv_row[constants.CSV_CHANGE_INST_NAME_COL_NO] + self.ta_cd = self.csv_row[constants.CSV_CHANGE_TA_CD_COL_NO] + self.explain = self.csv_row[constants.CSV_CHANGE_EXPLAIN_COL_NO] + self.emp_cd = self.csv_row[constants.CSV_CHANGE_EMP_CD_COL_NO] + self.emp_full_name = self.csv_row[constants.CSV_CHANGE_EMP_FULL_NAME_COL_NO] + self.inst_emp_start_date = self.csv_row[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO] + self.inst_emp_end_date = self.csv_row[constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO] + self.change_end_date = self.csv_row[constants.CSV_CHANGE_CHANGE_END_DATE_COL_NO] + self.comment = self.csv_row[constants.CSV_CHANGE_COMMENT] + + def csv_row_data(self) -> dict: + return {constants.CHANGE_INST_EMP_MAP[i]: self.csv_row[i] for i in range(len(self.csv_row))} + + def check_require(self) -> list[str]: + error_list = [] + if self.comment == '追加': + if len(self.bu_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_BU_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + if len(self.inst_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_INST_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + if len(self.ta_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_TA_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + if len(self.emp_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_EMP_CD_COL_NO], + constants.CSV_UP_NULL_ERR, 'が入力されておりません。']) + if len(self.inst_emp_start_date) == 0: + error_list.append([self.line_num, constants. + CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.inst_emp_end_date) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[ + constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + elif self.comment == '終了': + if len(self.inst_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_INST_CD_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.ta_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_TA_CD_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.inst_emp_start_date) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[ + constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.change_end_date) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[ + constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + elif self.comment == '担当者修正': + if len(self.inst_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_INST_CD_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.ta_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_TA_CD_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.emp_cd) == 0: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_EMP_CD_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + if len(self.inst_emp_start_date) == 0: + error_list.append([self.line_num, constants. + CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO], + constants.CSV_UP_NULL_ERR, + 'が入力されておりません。']) + else: + error_list.append([self.line_num, constants.CHANGE_INST_EMP_MAP[constants.CSV_CHANGE_COMMENT], + constants.CSV_UP_COMMENT_ERR, + 'のコメントが不正です。 「追加」「終了」「担当者修正」のいずれかを入力してください。']) + + return error_list + + def check_emp_cd_exists(self) -> list[str]: + error_list = [] + + if self.comment != '追加' and self.comment != '担当者修正': + return error_list + + if super().is_error_emp_cd(self.inst_emp_start_date) is True: + error_list.append([self.line_num, constants.NEW_INST_EMP_CSV_MAP[constants.CSV_NEW_EMP_CD_COL_NO], + constants.CSV_UP_NOT_EXIST_EMP_CD_ERR, '']) + return error_list + + def check_item_count(self) -> list[str]: + return super().check_csv_item_count(constants.CSV_CHANGE_COL_COUNT) + + def check_data_exists(self) -> list[str]: + error_list = [] + emp_chg_inst_count = super().emp_chg_inst_count(self.inst_emp_start_date) + if self.comment == '追加' and emp_chg_inst_count > 0: + error_list.append([self.line_num, '', constants.CSV_UP_ADD_DATA_DUP_ERR, '']) + elif (self.comment == '終了' or self.comment == '担当者修正') and emp_chg_inst_count == 0: + error_list.append([self.line_num, '', constants.CSV_UP_UPDATE_DATA_DUP_ERR, '']) + + return error_list + + def check_existing_date(self) -> list[str]: + return [] + + +class MasterMainteCSVItems: + """施設担当者CSVをループで回すためのもの""" + lines: list[MasterMainteCSVItem] + __i: int = 0 + header: list[str] + + def reset(self): + self.__i = 0 + + def __iter__(self): + return self + + def __next__(self) -> MasterMainteCSVItem: + if self.__i == len(self.lines): + raise StopIteration() + line = self.lines[self.__i] + self.__i += 1 + return line + + def __init__( + self, + file: TextIOWrapper, + csv_upload_form: MasterMainteCsvUpModel, + inst_cd_repository: MenteExistInstCdRepository, + emp_cd_repository: MenteExistEmpCdRepository, + bu_cd_repository: MenteExistBuCdRepository, + dummy_data_repository: MenteExistDummyDataRepository, + real_data_repository: MenteExistRealDataRepository, + emp_chg_inst_repository: MenteExistEmpChgInstRepository + ) -> None: + # self.header = file.readline().strip('\n').replace('"', '').split(',') + # reader = csv.DictReader(file, fieldnames=self.header) + reader = csv.reader(file) + csv_rows = [] + if csv_upload_form.select_function == 'new': + for line_num, row in enumerate(reader, start=0): + if line_num == 0: + continue + csv_rows.append(MasterMainteNewInstEmpCSVItem( + row, + csv_upload_form.select_table, + str(line_num), + inst_cd_repository, + emp_cd_repository, + bu_cd_repository, + dummy_data_repository, + real_data_repository, + emp_chg_inst_repository) + ) + elif csv_upload_form.select_function == 'change': + for line_num, row in enumerate(reader, start=0): + if line_num == 0: + continue + csv_rows.append(MasterMainteChangeInstEmpCSVItem( + row, + csv_upload_form.select_table, + str(line_num), + inst_cd_repository, + emp_cd_repository, + bu_cd_repository, + dummy_data_repository, + real_data_repository, + emp_chg_inst_repository) + ) + self.lines = csv_rows diff --git a/ecs/jskult-webapp/src/model/internal/master_mainte_insert_emp_chg.py b/ecs/jskult-webapp/src/model/internal/master_mainte_insert_emp_chg.py new file mode 100644 index 00000000..d709487f --- /dev/null +++ b/ecs/jskult-webapp/src/model/internal/master_mainte_insert_emp_chg.py @@ -0,0 +1,161 @@ +from abc import ABCMeta, abstractmethod +from src.repositories.mente_write_emp_chg_inst_repository import MenteWriteEmpChgInstRepository + +from src.system_var import constants + + +class MasterMainteInsertEmpChg(metaclass=ABCMeta): + insert_data: list[dict] + table_name: str + select_table_message: str + user_name: str + emp_chg_inst_repository: MenteWriteEmpChgInstRepository + + def __init__( + self, + insert_data, + table_name: str, + select_table_message: str, + user_name: str, + emp_chg_inst_repository: MenteWriteEmpChgInstRepository + ): + self.insert_data = insert_data + self.table_name = table_name # ダミー or 本番 + self.select_table_message = select_table_message + self.user_name = user_name + self.emp_chg_inst_repository = emp_chg_inst_repository + + def insert_emp_chg_inst(self): + error_list = [] + try: + self.emp_chg_inst_repository.connect() + self.emp_chg_inst_repository.begin() + (result_message, error_list) = self.write_emp_chg_inst_table() + if len(error_list) > 0: + self.emp_chg_inst_repository.rollback() + else: + self.emp_chg_inst_repository.commit() + except Exception: + self.emp_chg_inst_repository.rollback() #  一つでもエラーが発生したら終了するようにする場合はここで + + finally: + self.emp_chg_inst_repository.disconnect() + + return (result_message, error_list) + + def insert_emp_chg_inst_table(self, data, start_date, end_date): + self.emp_chg_inst_repository.insert_emp_chg_inst( + data['施設コード'], + data['領域コード'], + data['MUID'], + data['ビジネスユニットコード'], + start_date, + end_date, + self.user_name, + self.user_name, + self.table_name) + + @abstractmethod + def write_emp_chg_inst_table(self): + pass + + +class MasterMainteNewInsertEmpChg(MasterMainteInsertEmpChg): + + def __init__( + self, + insert_data_list: list[dict], + table_name: str, + select_table_message: str, + user_name: str, + emp_chg_inst_repository: MenteWriteEmpChgInstRepository + ): + super().__init__( + insert_data_list, + table_name, + select_table_message, + user_name, + emp_chg_inst_repository + ) + + def write_emp_chg_inst_table(self): + error_list = [] + + add_count = 0 + for row_no, data in enumerate(self.insert_data, start=1): + try: + self.insert_emp_chg_inst_table(data, data['適用開始日'], data['適用終了日']) + add_count += 1 + except Exception: + error_list.append([str(row_no), '', constants.CSV_UP_SQL_ERR, '']) # ここをどうする? + + result_message_list = [] + result_message_list.append('新規施設登録を行いました') + result_message_list.append('対象:' + self.select_table_message) + result_message_list.append('追加:' + str(add_count) + '件') + return (result_message_list, error_list) + + +class MasterMainteChangeInsertEmpChg(MasterMainteInsertEmpChg): + + def __init__( + self, + insert_data: list[dict], + table_name: str, + select_table_message: str, + user_name: str, + emp_chg_inst_repository: MenteWriteEmpChgInstRepository + + ): + super().__init__( + insert_data, + table_name, + select_table_message, + user_name, + emp_chg_inst_repository + ) + + def write_emp_chg_inst_table(self): + add_count = 0 + end_count = 0 + modify_count = 0 + error_list = [] # 例外が発生する仕組みなのでどうするか? + for row_no, data in enumerate(self.insert_data, start=1): + try: + if data['コメント'] == '追加': + self.insert_emp_chg_inst_table(data, data['施設担当_開始日'], data['施設担当_終了日']) + add_count += 1 + elif data['コメント'] == '終了': + self.__end_emp_chg_inst(data) + end_count += 1 + elif data['コメント'] == '担当者修正': + self.__modify_end_emp_chg_inst(data) + modify_count += 1 + except Exception: + error_list.append([str(row_no), '', constants.CSV_UP_SQL_ERR, '']) # ここをどうする? + + result_message_list = [] + result_message_list.append('施設担当者変更を行いました') + result_message_list.append('対象:' + self.select_table_message) + result_message_list.append('追加:' + str(add_count) + '件') + result_message_list.append('修正:' + str(modify_count) + '件') + result_message_list.append('終了:' + str(end_count) + '件') + return (result_message_list, error_list) + + def __end_emp_chg_inst(self, data: dict): + self.emp_chg_inst_repository.end_emp_chg_inst( + data['施設コード'], + data['領域コード'], + data['施設担当_開始日'], + data['終了日の変更'], + self.user_name, + self.table_name) + + def __modify_end_emp_chg_inst(self, data: dict): + self.emp_chg_inst_repository.modify_end_emp_chg_inst( + data['施設コード'], + data['領域コード'], + data['施設担当_開始日'], + data['MUID'], + self.user_name, + self.table_name) diff --git a/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py b/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py new file mode 100644 index 00000000..55f5a470 --- /dev/null +++ b/ecs/jskult-webapp/src/model/request/master_mainte_csvup.py @@ -0,0 +1,31 @@ +from typing import Optional, Annotated + +from fastapi import Form + +from src.util.sanitize import sanitize +from fastapi import File, UploadFile + +from src.model.request.request_base_model import RequestBaseModel + + +@sanitize +class MasterMainteCsvUpModel(RequestBaseModel): + csv_file: Optional[Annotated[UploadFile, File()]] + select_function: Optional[str] + select_table: Optional[str] + json_upload_data: Optional[str] + + @classmethod + def as_form( + cls, + 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), + ): + return cls( + csv_file=ctrl_csv_file, + select_function=ctrl_select_function, + select_table=ctrl_select_table, + json_upload_data=ctrl_json_upload_data + ) diff --git a/ecs/jskult-webapp/src/model/view/inst_emp_csv_upload_view_model.py b/ecs/jskult-webapp/src/model/view/inst_emp_csv_upload_view_model.py index 64bde407..9d29f508 100644 --- a/ecs/jskult-webapp/src/model/view/inst_emp_csv_upload_view_model.py +++ b/ecs/jskult-webapp/src/model/view/inst_emp_csv_upload_view_model.py @@ -1,5 +1,62 @@ +from typing import Optional + from pydantic import BaseModel +from src.model.view.mainte_csv_upload_model import CsvUploadModel +from src.model.view.mainte_csv_error_model import CsvErrorModel +from src.system_var import constants class InstEmpCsvUploadViewModel(BaseModel): subtitle: str = '施設担当者データCSVアップロード' + is_verified: Optional[bool] + is_insert: Optional[bool] + error_list: Optional[list[CsvErrorModel]] + select_function: Optional[str] + select_table: Optional[str] + csv_file_name: Optional[str] + csv_upload_list: Optional[list[CsvUploadModel]] + json_upload_data: Optional[str] + result_message_list: Optional[list[str]] + dialog_msg: Optional[str] + + def select_function_message(self): + return self.__new_inst_emp() if self.select_function == 'new' else self.__change_inst_emp() + + def select_table_message(self): + return self.__dummy_table() if self.select_table == 'dummy' else self.__real_table() + + def upload_data_columns(self) -> list[str]: + return self.__inst_emp_columns() + + def is_select_function_empty(self): + return self.select_function is None or len(self.select_function) == 0 + + def is_select_table_empty(self): + return self.select_table is None or len(self.select_table) == 0 + + def is_error_list_empty(self): + return self.error_list is None or len(self.error_list) == 0 + + def csv_data_count(self): + return 0 if self.csv_upload_list is None else len(self.csv_upload_list) + + def __inst_emp_columns(self) -> list[str]: + if self.select_function == 'new': + return constants.NEW_INST_EMP_CSV_MAP + if self.select_function == 'change': + return constants.CHANGE_INST_EMP_MAP + return [] + + # 定数にした方が良さそう + + def __real_table(self): + return '本番テーブル' + + def __dummy_table(self): + return 'ダミーテーブル' + + def __new_inst_emp(self): + return '新規施設登録' + + def __change_inst_emp(self): + return '施設担当者変更' diff --git a/ecs/jskult-webapp/src/model/view/mainte_csv_error_model.py b/ecs/jskult-webapp/src/model/view/mainte_csv_error_model.py new file mode 100644 index 00000000..4fb4e241 --- /dev/null +++ b/ecs/jskult-webapp/src/model/view/mainte_csv_error_model.py @@ -0,0 +1,30 @@ +from pydantic import BaseModel +from typing import Optional +from src.system_var import constants + + +class CsvErrorModel(BaseModel): + row_no: Optional[str] + item_name: Optional[str] + message: Optional[str] + error_code: Optional[str] + + def __init__(self, row_no: str, item_name: str, error_code: str, message: str) -> None: + super().__init__(row_no=row_no, item_name=item_name, + error_code=error_code, message=message) + + # 確認のため途中まで実装 エラーコードが無いと、メッセージの編集が適切にできない場合あり + + def error_message(self): + error_message: str = '' + if self.error_code == constants.CSV_UP_NULL_ERR: + error_message = self.row_no + '行目の' + self.item_name + 'が入力されておりません。' + elif self.error_code == constants.CSV_UP_NOT_EXIST_INST_CD_ERR: + error_message = self.row_no + '行目の施設コードは施設マスタに存在しないコードです。' + elif self.error_code == constants.CSV_UP_NOT_EXIST_EMP_CD_ERR: + error_message = self.row_no + '行目のMUIDは従業員マスタに存在しない もしくは 適用期間外のIDです。' + elif self.error_code == constants.CSV_UP_NOT_EXIST_BU_CD_ERR: + error_message = self.row_no + '行目のビジネスユニットコードはビジネスユニットマスタに存在しないコードです。' + elif self.error_code == constants.CSV_UP_SQL_ERR: + error_message = self.row_no + '行目がSQL実行エラーです。Excelファイルを確認してください。' + return error_message diff --git a/ecs/jskult-webapp/src/model/view/mainte_csv_upload_model.py b/ecs/jskult-webapp/src/model/view/mainte_csv_upload_model.py new file mode 100644 index 00000000..2c227470 --- /dev/null +++ b/ecs/jskult-webapp/src/model/view/mainte_csv_upload_model.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel +from typing import Optional + + +class CsvUploadModel(BaseModel): + subtitle: str = '施設担当者データCSVアップロード' + csv_row: Optional[dict] diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_bu_cd_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_bu_cd_repository.py new file mode 100644 index 00000000..2305f884 --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_bu_cd_repository.py @@ -0,0 +1,29 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistBuCdRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + src05.bu + WHERE + bu.bu_cd = :bu_cd + """ + + def fetch_count(self, bu_cd) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL + result = self._database.execute_select(query, {'bu_cd': bu_cd}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_dummy_data_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_dummy_data_repository.py new file mode 100644 index 00000000..bb892aa2 --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_dummy_data_repository.py @@ -0,0 +1,34 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistDummyDataRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + src05.emp_chg_inst_wrk + WHERE + inst_cd = :instCd + AND ta_cd = :taCd + AND start_date = :startDate + """ + + def fetch_count(self, inst_cd, ta_cd, start_date) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL + result = self._database.execute_select(query, + {'instCd': inst_cd, + 'taCd': ta_cd, + 'startDate': start_date}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_emp_cd_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_emp_cd_repository.py new file mode 100644 index 00000000..d7619719 --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_emp_cd_repository.py @@ -0,0 +1,32 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistEmpCdRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + src05.emp + WHERE + emp.EMP_CD = :emp_cd + AND str_to_date(emp.start_date, '%Y%m%d') <= str_to_date(:start_date1, '%Y%m%d') + AND str_to_date(:start_date2 ,'%Y%m%d') <= str_to_date(emp.END_DATE ,'%Y%m%d') + """ + + def fetch_count(self, emp_cd, start_date1, start_date2) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL + result = self._database.execute_select(query, {'emp_cd': emp_cd, 'start_date1': start_date1, + 'start_date2': start_date2}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_emp_chg_inst_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_emp_chg_inst_repository.py new file mode 100644 index 00000000..4c321de7 --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_emp_chg_inst_repository.py @@ -0,0 +1,32 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistEmpChgInstRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + {table_name} + WHERE + inst_cd = :inst_cd + AND ta_cd = :ta_cd + AND start_date = :start_date + """ + + def fetch_count(self, inst_cd, ta_cd, start_date, table_name) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL.format(table_name=table_name) + result = self._database.execute_select(query, {'inst_cd': inst_cd, 'ta_cd': ta_cd, + 'start_date': start_date}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_inst_cd_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_inst_cd_repository.py new file mode 100644 index 00000000..e360e494 --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_inst_cd_repository.py @@ -0,0 +1,29 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistInstCdRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + src05.mst_inst + WHERE + mst_inst.inst_cd = :instcd + """ + + def fetch_count(self, instcd) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL + result = self._database.execute_select(query, {'instcd': instcd}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_exist_real_data_repository.py b/ecs/jskult-webapp/src/repositories/mente_exist_real_data_repository.py new file mode 100644 index 00000000..bf74305c --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_exist_real_data_repository.py @@ -0,0 +1,34 @@ +from src.repositories.base_repository import BaseRepository +from src.model.db.master_mente_count import MasterMenteCountModel + + +class MenteExistRealDataRepository(BaseRepository): + + FETCH_COUNT_SQL = """\ + SELECT + COUNT(*) AS count + FROM + src05.emp_chg_inst + WHERE + inst_cd = :instCd + AND ta_cd = :taCd + AND start_date = :startDate + """ + + def fetch_count(self, inst_cd, ta_cd, start_date) -> MasterMenteCountModel: + try: + self._database.connect() + query = self.FETCH_COUNT_SQL + result = self._database.execute_select(query, + {'instCd': inst_cd, + 'taCd': ta_cd, + 'startDate': start_date}) + models = [MasterMenteCountModel(**r) for r in result] + if len(models) == 0: + return 0 + return models[0].count + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + finally: + self._database.disconnect() diff --git a/ecs/jskult-webapp/src/repositories/mente_write_emp_chg_inst_repository.py b/ecs/jskult-webapp/src/repositories/mente_write_emp_chg_inst_repository.py new file mode 100644 index 00000000..4a2856ec --- /dev/null +++ b/ecs/jskult-webapp/src/repositories/mente_write_emp_chg_inst_repository.py @@ -0,0 +1,124 @@ +from src.repositories.base_repository import BaseRepository + + +class MenteWriteEmpChgInstRepository(BaseRepository): + + def connect(self): + self._database.connect() + + def begin(self): + self._database.begin() + + def commit(self): + self._database.commit() + + def rollback(self): + self._database.rollback() + + def disconnect(self): + self._database.disconnect() + + INSERT_SQL = """\ + INSERT INTO {table_name} + ( + inst_cd, + ta_cd, + emp_cd, + bu_cd, + start_date, + end_date, + main_chg_flg, + enabled_flg, + creater, + create_date, + updater, + update_date + ) + VALUES ( + :inst_cd, + :ta_cd, + :emp_cd, + :bu_cd, + :start_date, + :end_date, + '1', + 'Y', + :create_user_name, + NOW(), + :update_user_name, + NOW() + ) + """ + + def insert_emp_chg_inst(self, inst_cd, ta_cd, emp_cd, bu_cd, start_date, + end_date, create_user_name, update_user_name, table_name): + try: + query = self.INSERT_SQL.format(table_name=table_name) + self._database.execute(query, { + 'inst_cd': inst_cd, + 'ta_cd': ta_cd, + 'emp_cd': emp_cd, + 'bu_cd': bu_cd, + 'start_date': start_date, + 'end_date': end_date, + 'create_user_name': create_user_name, + 'update_user_name': update_user_name + }) + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + + UPDATE_SQL = """\ + UPDATE + {table_name} + SET + end_date = :end_date, + updater = :update_user_name, + update_date = NOW() + WHERE + inst_cd = :inst_cd + and ta_cd = :ta_cd + and start_date = :start_date + """ + + def end_emp_chg_inst(self, inst_cd, ta_cd, start_date, + end_date, update_user_name, table_name): + try: + query = self.UPDATE_SQL.format(table_name=table_name) + self._database.execute(query, { + 'inst_cd': inst_cd, + 'ta_cd': ta_cd, + 'start_date': start_date, + 'end_date': end_date, + 'update_user_name': update_user_name + }) + except Exception as e: + print(f"[ERROR] DB Error : Exception={e.args}") + raise e + + UPDATE_SQL = """\ + UPDATE + {table_name} + SET + emp_cd = :emp_cd, + updater = :update_user_name, + update_date = now() + where + inst_cd = :inst_cd + and ta_cd = :ta_cd + and start_date = :start_date + """ + + def modify_end_emp_chg_inst(self, inst_cd, ta_cd, start_date, emp_cd, update_user_name, table_name): + try: + query = self.UPDATE_SQL.format(table_name=table_name) + self._database.execute(query, { + 'inst_cd': inst_cd, + 'ta_cd': ta_cd, + 'start_date': start_date, + 'emp_cd': emp_cd, + 'update_user_name': update_user_name + }) + except Exception as e: + print(f"[ERROR] 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 new file mode 100644 index 00000000..f68cba6b --- /dev/null +++ b/ecs/jskult-webapp/src/services/master_mainte_service.py @@ -0,0 +1,142 @@ +import json +import html +from io import TextIOWrapper +from src.aws.aws_api_client import AWSAPIClient +from src.repositories.base_repository import BaseRepository +from src.services.base_service import BaseService +from src.model.internal.master_mainte_csv import MasterMainteCSVItems +from src.model.internal.master_mainte_insert_emp_chg import MasterMainteChangeInsertEmpChg +from src.model.internal.master_mainte_insert_emp_chg import MasterMainteNewInsertEmpChg +from src.model.view.inst_emp_csv_upload_view_model import InstEmpCsvUploadViewModel +from src.model.request.master_mainte_csvup import MasterMainteCsvUpModel +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 +from src.repositories.mente_exist_inst_cd_repository import MenteExistInstCdRepository +from src.repositories.mente_exist_bu_cd_repository import MenteExistBuCdRepository +from src.repositories.mente_exist_emp_cd_repository import MenteExistEmpCdRepository +from src.repositories.mente_exist_dummy_data_repository import MenteExistDummyDataRepository +from src.repositories.mente_exist_real_data_repository import MenteExistRealDataRepository +from src.repositories.mente_exist_emp_chg_inst_repository import MenteExistEmpChgInstRepository +from src.repositories.mente_write_emp_chg_inst_repository import MenteWriteEmpChgInstRepository + +logger = get_logger('マスターメンテ') + + +class MasterMainteService(BaseService): + REPOSITORIES = { + 'inst_cd_repository': MenteExistInstCdRepository, + 'emp_cd_repository': MenteExistEmpCdRepository, + 'bu_cd_repository': MenteExistBuCdRepository, + 'dummy_data_repository': MenteExistDummyDataRepository, + 'real_data_repository': MenteExistRealDataRepository, + 'emp_chg_inst_repository': MenteExistEmpChgInstRepository, + 'write_emp_chg_inst_repository': MenteWriteEmpChgInstRepository + } + + inst_cd_repository: MenteExistInstCdRepository + emp_cd_repository: MenteExistEmpCdRepository + bu_cd_repository: MenteExistBuCdRepository + dummy_data_repository: MenteExistDummyDataRepository + real_data_repository: MenteExistRealDataRepository + emp_chg_inst_repository: MenteExistEmpChgInstRepository + write_emp_chg_inst_repository: MenteWriteEmpChgInstRepository + + def __init__(self, repositories: dict[str, BaseRepository], clients: dict[str, AWSAPIClient]) -> None: + super().__init__(repositories, clients) + self.inst_cd_repository = repositories['inst_cd_repository'] + self.emp_cd_repository = repositories['emp_cd_repository'] + self.bu_cd_repository = repositories['bu_cd_repository'] + self.dummy_data_repository = repositories['dummy_data_repository'] + self.real_data_repository = repositories['real_data_repository'] + self.emp_chg_inst_repository = repositories['emp_chg_inst_repository'] + self.write_emp_chg_inst_repository = repositories['write_emp_chg_inst_repository'] + + def prepare_mainte_csv_up_view(self, + file: TextIOWrapper, + csv_file_name: str, + csv_upload_form: MasterMainteCsvUpModel) -> InstEmpCsvUploadViewModel: + + csv_items = MasterMainteCSVItems( + file, + csv_upload_form, + self.inst_cd_repository, + self.emp_cd_repository, + self.bu_cd_repository, + self.dummy_data_repository, + self.real_data_repository, + self.emp_chg_inst_repository + ) + + error_list = [] + for row_item in csv_items: + error_list.extend([CsvErrorModel(data[0], data[1], data[2], data[3]) for data in row_item.validate()]) # 微妙 + + csv_items.reset() + csv_upload_list = [] + json_upload_data = '' + if len(error_list) == 0: + csv_upload_list: list[CsvUploadModel] = [CsvUploadModel( + csv_row=row_item.csv_row_data()) for row_item in csv_items] + + # json作成 + json_upload_data = json.dumps([model.csv_row for model in csv_upload_list], ensure_ascii=False) + + mainte_csv_up = InstEmpCsvUploadViewModel( + is_verified=True, + error_list=error_list, + select_function=csv_upload_form.select_function, + select_table=csv_upload_form.select_table, + csv_upload_list=csv_upload_list, + json_upload_data=json_upload_data, + csv_file_name=csv_file_name + ) + return mainte_csv_up + + def prepare_mainte_new_inst_view(self, + user_name: str, + csv_upload_form: MasterMainteCsvUpModel) -> InstEmpCsvUploadViewModel: + + if csv_upload_form.select_table == 'dummy': + table_name = 'src05.emp_chg_inst_wrk' + selected_table_msg = 'ダミーテーブル' + elif csv_upload_form.select_table == 'real': + table_name = 'src05.emp_chg_inst' + selected_table_msg = '本番テーブル' + # else: + # 例外? + + csv_data_list = json.loads(html.unescape(csv_upload_form.unescape().json_upload_data)) + + if csv_upload_form.select_function == 'new': + insert_emp_chg = MasterMainteNewInsertEmpChg( + csv_data_list, + table_name, + selected_table_msg, + user_name, + self.write_emp_chg_inst_repository) + elif csv_upload_form.select_function == 'change': + insert_emp_chg = MasterMainteChangeInsertEmpChg( + csv_data_list, + table_name, + selected_table_msg, + user_name, + self.write_emp_chg_inst_repository + ) + # else: + # 例外を発生させる? + + (result_message_list, raw_error_list) = insert_emp_chg.insert_emp_chg_inst() + + error_list = [] + error_list.extend([CsvErrorModel(data[0], data[1], data[2], data[3]) for data in raw_error_list]) + + if result_message_list is None: + result_message_list.append('DB接続エラー') + + mainte_csv_up = InstEmpCsvUploadViewModel( + is_insert=True, + result_message_list=result_message_list, + error_list=error_list + ) + return mainte_csv_up diff --git a/ecs/jskult-webapp/src/static/function/businessLogicScript.js b/ecs/jskult-webapp/src/static/function/businessLogicScript.js index 36171aad..bd39eafd 100644 --- a/ecs/jskult-webapp/src/static/function/businessLogicScript.js +++ b/ecs/jskult-webapp/src/static/function/businessLogicScript.js @@ -250,4 +250,69 @@ function checkNumberOnlyForm($this) str=str.replace(/[^\d]/,""); } $this.value=str; -} \ No newline at end of file +} + +// メニューへボタンの関数 +// 機能概要:マスターメンテメニュー画面に遷移する +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); +} + +// 確認ダイアログ +function confirmDialog(strMesssage) { + var result = confirm(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 === ""){ + validFlg = true; + } + + if (validFlg == true) { + document.getElementById("confirm").disabled = true; + } + else { + document.getElementById("confirm").disabled = false; + } +} + diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 604acfe5..0e0a8b0a 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -134,3 +134,110 @@ LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。
再度Loginするか、
管理者にお問い合わせください。', LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。
再度Loginするか、
管理者に問い合わせてください。' } + +NEW_INST_EMP_CSV_MAP = [ + '施設コード', + '施設名', + '領域コード', + 'MUID', + '担当者名(姓)', + '担当者名(名)', + 'ビジネスユニットコード', + '適用開始日', + '適用終了日' +] + +CHANGE_INST_EMP_MAP = [ + 'ビジネスユニットコード', # A + 'ビジネスユニット名', # B + '組織コード', # C + '組織名略称', # D + '施設コード', # E + '施設名', # F + '領域コード', # G + '説明', # H + 'MUID', # I + '担当者名', # J + '施設担当_開始日', # K + '施設担当_終了日', # L + '終了日の変更', # M + 'コメント' # N +] + +# 新規施設担当者登録CSV +# 施設コードの列No +CSV_NEW_INST_CD_COL_NO = 0 +# 施設名の列No +CSV_NEW_INST_NAME_COL_NO = 1 +# 領域コードの列No +CSV_NEW_TA_CD_COL_NO = 2 +# MUIDの列No +CSV_NEW_EMP_CD_COL_NO = 3 +# 担当者名(姓)の列No +CSV_NEW_EMP_NAME_FAMILY_COL_NO = 4 +# 担当者名(名)の列No +CSV_NEW_EMP_NAME_FIRST_COL_NO = 5 +# ビジネスユニットコードの列No +CSV_NEW_BU_CD_COL_NO = 6 +# 適用開始日の列No +CSV_NEW_START_DATE = 7 +# 適用終了日の列No +CSV_NEW_END_DATE = 8 + +# 施設担当者変更登録CSV +# ビジネスユニットコードの列No +CSV_CHANGE_BU_CD_COL_NO = 0 +# ビジネスユニット名の列No +CSV_CHANGE_BU_NAME_COL_NO = 1 +# 組織コードの列No +CSV_CHANGE_ORG_CD_COL_NO = 2 +# 組織名略称の列No +CSV_CHANGE_ORG_SHORT_NAME_COL_NO = 3 +# 施設コードの列No +CSV_CHANGE_INST_CD_COL_NO = 4 +# 施設名の列No +CSV_CHANGE_INST_NAME_COL_NO = 5 +# 領域コードの列No +CSV_CHANGE_TA_CD_COL_NO = 6 +# 説明の列No +CSV_CHANGE_EXPLAIN_COL_NO = 7 +# MUIDの列No +CSV_CHANGE_EMP_CD_COL_NO = 8 +# 担当者名の列No +CSV_CHANGE_EMP_FULL_NAME_COL_NO = 9 +# 施設担当_開始日の列No +CSV_CHANGE_INST_EMP_START_DATE_COL_NO = 10 +# 施設担当_終了日の列No +CSV_CHANGE_INST_EMP_END_DATE_COL_NO = 11 +# 終了日の変更の列No +CSV_CHANGE_CHANGE_END_DATE_COL_NO = 12 +# コメントの列No +CSV_CHANGE_COMMENT = 13 + + +# エラーコード +CSV_UP_NULL_ERR = 'nullError' +CSV_UP_COMMENT_ERR = 'commentError' +CSV_UP_NOT_EXIST_INST_CD_ERR = 'instCdErr' +CSV_UP_NOT_EXIST_EMP_CD_ERR = 'empCdErr' +CSV_UP_NOT_EXIST_BU_CD_ERR = 'buCdErr' +CSV_UP_ITEM_CNT_ERR = 'itemCntErr' +CSV_UP_FILE_TYPE_ERR = 'fileTypeErr' +CSV_UP_FILEN_EXIST_ERR = 'filenExistErr' +CSV_UP_SQL_ERR = 'sqlErr' +CSV_UP_NEW_COMPARE_DATE_ERR = 'newCompareDateErr' +CSV_UP_ADD_COMPARE_DATE_ERR = 'addCompareDateErr' +CSV_UP_END_COMPARE_DATE_ERR = 'endCompareDateErr' +CSV_UP_START_DATE_REAL_ERR = 'startDateRealErr' +CSV_UP_END_DATE_REAL_ERR = 'endDateRealErr' +CSV_UP_INST_EMPSTART_DATE_REAL_ERR = 'instEmpStartDateRealErr' +CSV_UP_INST_EMP_END_DATE_REAL_ERR = 'instEmpEndDateRealErr' +CSV_UP_CHANGE_END_DATE_REAL_ERR = 'changeEndDateRealErr' +CSV_UP_NEW_DATA_DUP_ERR = 'newDataDupErr' +CSV_UP_ADD_DATA_DUP_ERR = 'addDataDupErr' +CSV_UP_UPDATE_DATA_DUP_ERR = 'updateDataDupErr' +CSV_UP_INPUT_DATA_ZERO_ERR = 'inputDataZeroErr' + +# CSVの列数 +CSV_NEW_COL_COUNT = 9 +CSV_CHANGE_COL_COUNT = 14 diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html index 7e84fd4c..1209f8e2 100644 --- a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html +++ b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html @@ -1,12 +1,177 @@ - {% with subtitle = view.subtitle %} + {% with subtitle = mainte_csv_dl.subtitle %} {% include '_header.html' %} {% endwith %} + <!-- <?php echo $instEmpCsvDL ?> --> + + + + + +

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

+ +

+ + + + + +
+

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + ~ + + + + ~ + +
+ + + + + ~ + + + + ~ + +
+ + +
+
+

+ +

+

+ + + + diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvUL.html b/ecs/jskult-webapp/src/templates/instEmpCsvUL.html index 9ec84207..2c318134 100644 --- a/ecs/jskult-webapp/src/templates/instEmpCsvUL.html +++ b/ecs/jskult-webapp/src/templates/instEmpCsvUL.html @@ -1,13 +1,332 @@ - {% with subtitle = view.subtitle %} + {% with subtitle = mainte_csv_up.subtitle %} {% include '_header.html' %} {% endwith %} + + + + {% if not mainte_csv_up.is_verified %} + + {% endif %} -

施設担当者データCSVアップロード

+ +

+ + + + + +
施設担当者データCSVアップロード + {% if mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() %} + + {% else %} + + {% endif %} +
+

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
機能: + + + +
登録テーブル: + + + +
登録Excel: + {% if mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() %} + {{mainte_csv_up.csv_file_name}} + {% else %} + + {% endif %} + + {% if mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() and mainte_csv_up.select_table == 'real' %} + +
本番テーブルが選択されています
+ {% elif mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() and mainte_csv_up.select_table == 'dummy' %} + + + {% else %} + + + {% endif %} +
+{% if mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() %} + + + +{% endif %} +
+

+ +

+ {% if not mainte_csv_up.is_error_list_empty() %} +
+ {% for error in mainte_csv_up.error_list %} + {{error.error_message()}}
+ {% endfor %} +
+ {% elif mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() %} +
+
件数:{{mainte_csv_up.csv_data_count()}}件
+ + + + + {% for column_name in mainte_csv_up.upload_data_columns() %} + + {% endfor %} + + {% for item in mainte_csv_up.csv_upload_list %} + + {% for key, value in item.csv_row.items() %} + + {% endfor %} + + {% endfor %} + +
{{column_name}}
{{value}}
+
+ {% elif mainte_csv_up.is_insert %} +
+ {% for message in mainte_csv_up.result_message_list %} + {{ message }}
+ {% endfor %} +
+ {% endif %} + + + + + +

diff --git a/ecs/jskult-webapp/src/templates/tableOverride.html b/ecs/jskult-webapp/src/templates/tableOverride.html index e473b469..2d6c624f 100644 --- a/ecs/jskult-webapp/src/templates/tableOverride.html +++ b/ecs/jskult-webapp/src/templates/tableOverride.html @@ -5,8 +5,68 @@ {% include '_header.html' %} {% endwith %} + <!-- <?php echo $tableOverride; ?> --> +

テーブル上書きコピー

+ + +

+ + + + + +
+

+ + + + + + + + + +
+ +
+ +
+ + + + + +