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 ea972ad6..046fc4ab 100644
--- a/ecs/jskult-webapp/src/controller/master_mainte.py
+++ b/ecs/jskult-webapp/src/controller/master_mainte.py
@@ -1,8 +1,11 @@
+from io import BytesIO, TextIOWrapper
+from typing import Optional
+
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import HTMLResponse
from starlette import status
-
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
@@ -13,9 +16,15 @@ 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 src.model.request.master_mainte_csvdl import MasterMainteCsvDlModel
+
+
+logger = get_logger('マスターメンテ')
router = APIRouter()
router.route_class = AuthenticatedRoute
@@ -85,7 +94,7 @@ 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()
# セッション書き換え
session.update(
actions=[
@@ -98,14 +107,118 @@ 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)
+
+ # 画面表示用のモデル
+ error_message_list = []
+ content_type: str = csv_upload_form.csv_file.content_type.strip()
+ if csv_upload_form.csv_file.size == 0:
+ error_message_list.append('選択されたファイルが見つかりませんでした。')
+ elif content_type != 'text/csv' and content_type != 'application/vnd.ms-excel' and content_type != 'application/octet-stream':
+ error_message_list.append('選択されたファイル形式が"csv"ではありません。')
+ elif csv_upload_form.csv_file.size >= constants.MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE:
+ error_message_list.append('選択されたCSVファイルサイズが大きいです。100MB未満にしてください。')
+ else:
+ mainte_csv_up = master_mainte_service.prepare_mainte_csv_up_view(
+ TextIOWrapper(BytesIO(await csv_upload_form.csv_file.read()), encoding='utf-8'),
+ csv_upload_form.csv_file.filename,
+ csv_upload_form)
+
+ if len(error_message_list) > 0:
+ mainte_csv_up = InstEmpCsvUploadViewModel(
+ is_verified=True,
+ error_message_list=error_message_list,
+ select_function=csv_upload_form.select_function,
+ select_table=csv_upload_form.select_table)
+
+ # セッション書き換え
+ 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))
@@ -125,7 +238,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=[
@@ -138,7 +253,77 @@ 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 = master_mainte_service.search_emp_chg_inst_data(csv_download_form)
+
+ (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(
+ 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_from=csv_download_form.apply_date_from,
+ 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.shape[0],
+ 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}
)
@@ -165,7 +350,7 @@ def table_override_view(
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BACKUP_PROCESSING)
# 画面表示用のモデル
- view_model = TableOverrideViewModel()
+ table_override = TableOverrideViewModel()
# セッション書き換え
session.update(
actions=[
@@ -178,7 +363,49 @@ def table_override_view(
'tableOverride.html',
{
'request': request,
- 'view': view_model
+ 'table_override': table_override
+ },
+ headers={'session_key': session.session_key}
+ )
+ return templates_response
+
+
+@router.post('/tableOverride', response_class=HTMLResponse)
+def table_override_result_view(
+ request: Request,
+ 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)
+
+ # 画面表示用のモデル
+ table_override = master_mainte_service.copy_data_real_to_dummy()
+
+ # セッション書き換え
+ 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(
+ 'tableOverride.html',
+ {
+ 'request': request,
+ 'table_override': table_override
},
headers={'session_key': session.session_key}
)
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..e288ce3a
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/internal/master_mainte_csv.py
@@ -0,0 +1,572 @@
+import csv
+import json
+
+from io import TextIOWrapper
+from datetime import datetime
+from abc import ABCMeta, abstractmethod
+from src.system_var import constants
+from src.util.string_util import is_not_empty
+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.logging.get_logger import get_logger
+
+logger = get_logger('マスターメンテ')
+
+
+class MasterMainteCSVItem(metaclass=ABCMeta):
+
+ csv_row: list[str]
+ table_name: str
+ line_num: str
+ mst_inst_repository: MstInstRepository
+ emp_master_repository: EmpMasterRepository
+ bu_master_repository: BuMasterRepository
+ emp_chginst_repository: EmpChgInstRepository
+
+ def __init__(
+ self,
+ csv_row: list[str],
+ table_name: str,
+ line_num: str,
+ mst_inst_repository: MstInstRepository,
+ emp_master_repository: EmpMasterRepository,
+ bu_master_repository: BuMasterRepository,
+ emp_chginst_repository: EmpChgInstRepository
+ ):
+ self.csv_row = csv_row
+ self.table_name = table_name
+ self.line_num = line_num
+ self.mst_inst_repository = mst_inst_repository
+ self.emp_master_repository = emp_master_repository
+ self.bu_master_repository = bu_master_repository
+ self.emp_chginst_repository = emp_chginst_repository
+
+ def validate(self) -> list[str]:
+ """
+ 項目のバリデーションを行うテンプレートメソッド\n
+ 各チェックロジックはサブクラスで実装する
+ エラーが有る場合、[行数、項目名: エラー内容]のリストを返す
+ """
+ error_list = []
+ # 項目数チェック
+ error_list.extend(self.check_item_count())
+ if len(error_list) == 0:
+ # 必須チェック 及び コメントエラーチェック
+ 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_data_exists())
+
+ # エラーのないリストを省いて返す
+ error_list = [error for error in error_list if len(error) != 0]
+ return error_list
+
+ def check_csv_item_count(self, item_count: int) -> list[str]:
+ error_list = []
+
+ if not len(self.csv_row) == item_count:
+ error_list.append(f'{self.line_num}行目の項目数が一致しません。項目数を確認してください。')
+
+ return error_list
+
+ def emp_chg_inst_count(self, start_date: str):
+ return self.emp_chginst_repository.fetch_count(self.inst_cd, self.ta_cd, start_date, self.table_name)
+
+ def is_exist_emp_cd(self, start_date: str) -> bool:
+ if start_date is None or len(start_date) == 0:
+ return False
+ if self.emp_master_repository.fetch_count(self.emp_cd, start_date) == 0:
+ return True
+ return False
+
+ def is_exist_inst_cd(self) -> bool:
+ return True if self.mst_inst_repository.fetch_count(self.inst_cd) > 0 else False
+
+ def is_exist_bu_cd(self) -> bool:
+ return True if self.bu_master_repository.fetch_count(self.bu_cd) > 0 else False
+
+ def make_require_error_message(self, line_num: str, col_name: str) -> str:
+ return f'{line_num}行目の{col_name}が入力されておりません。'
+
+ def __parse_str_to_date(self, check_date: str) -> tuple[bool, datetime]:
+ try:
+ check_date_time: datetime = datetime.strptime(check_date, '%Y%m%d')
+ except Exception as e:
+ logger.debug(f'適用期間の日付が不正{e}')
+ return (False, None)
+
+ try:
+ reverse_check_date: str = check_date_time.strftime('%Y%m%d')
+ except Exception as e:
+ logger.debug(f'適用期間の日付が不正{e}')
+ return (False, None)
+
+ if check_date != reverse_check_date:
+ return (False, None)
+
+ return (True, check_date_time)
+
+ def check_term_date(self,
+ start_date: str,
+ end_date: str,
+ start_date_col_name: str,
+ end_date_col_name: str) -> tuple[list[str], datetime, datetime]:
+ error_list = []
+
+ start_date_time: datetime = None
+ end_date_time: datetime = None
+ if is_not_empty(start_date):
+ (result, start_date_time) = self.__parse_str_to_date(start_date)
+ if result is False:
+ error_list.append(f'{self.line_num}行目の{start_date_col_name}が実在しない日付になっています。')
+ if is_not_empty(end_date):
+ (result, end_date_time) = self.__parse_str_to_date(end_date)
+ if result is False:
+ error_list.append(f'{self.line_num}行目の{end_date_col_name}が実在しない日付になっています。')
+
+ return (error_list, start_date_time, end_date_time)
+
+ def get_csv_value(self, column_no: int):
+ try:
+ column_value = self.csv_row[column_no]
+ except IndexError:
+ column_value = ''
+
+ return column_value
+
+ @abstractmethod
+ def csv_row_data(self) -> dict:
+ pass
+ ...
+
+ @abstractmethod
+ def check_require(self) -> list[str]:
+ """必須チェック"""
+ pass
+ ...
+
+ @abstractmethod
+ def check_inst_cd_exists(self) -> list[str]:
+ """InstCD存在チェック"""
+ pass
+ ...
+
+ @abstractmethod
+ def check_emp_cd_exists(self) -> list[str]:
+ """MUID存在チェック"""
+ pass
+ ...
+
+ @abstractmethod
+ def check_bu_cd_exists(self) -> list[str]:
+ """BuCd存在チェック"""
+ pass
+ ...
+
+ @abstractmethod
+ def check_existing_date(self) -> list[str]:
+ """適用開始日 < 適用終了日、実在日チェック"""
+
+ @abstractmethod
+ def check_item_count(self) -> list[str]:
+ """項目数チェック"""
+ pass
+ ...
+
+ @abstractmethod
+ def check_data_exists(self) -> list[str]:
+ """データ存在チェック"""
+ pass
+ ...
+
+
+class MasterMainteNewInstEmpCSVItem(MasterMainteCSVItem):
+ """新規施設担当者登録CSV"""
+ inst_name: str
+ emp_name_family: str
+ emp_name_first: str
+ start_date: str
+ end_date: str
+
+ def __init__(
+ self,
+ csv_row: list[str],
+ table_name: str,
+ line_num: str,
+ mst_inst_repository: MstInstRepository,
+ emp_master_repository: EmpMasterRepository,
+ bu_master_repository: BuMasterRepository,
+ emp_chginst_repository: EmpChgInstRepository
+ ):
+ super().__init__(
+ csv_row,
+ table_name,
+ line_num,
+ mst_inst_repository,
+ emp_master_repository,
+ bu_master_repository,
+ emp_chginst_repository
+ )
+ self.inst_cd = super().get_csv_value(constants.CSV_NEW_INST_CD_COL_NO)
+ self.inst_name = super().get_csv_value(constants.CSV_NEW_INST_NAME_COL_NO)
+ self.ta_cd = super().get_csv_value(constants.CSV_NEW_TA_CD_COL_NO)
+ self.emp_cd = super().get_csv_value(constants.CSV_NEW_EMP_CD_COL_NO)
+ self.emp_name_family = super().get_csv_value(constants.CSV_NEW_EMP_NAME_FAMILY_COL_NO)
+ self.emp_name_first = super().get_csv_value(constants.CSV_NEW_EMP_NAME_FIRST_COL_NO)
+ self.bu_cd = super().get_csv_value(constants.CSV_NEW_BU_CD_COL_NO)
+ self.start_date = super().get_csv_value(constants.CSV_NEW_START_DATE)
+ self.end_date = super().get_csv_value(constants.CSV_NEW_END_DATE)
+
+ def csv_row_data(self) -> dict:
+ return {constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[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.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_INST_CD_COL_NO]))
+ if len(self.ta_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_TA_CD_COL_NO]))
+ if len(self.emp_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_EMP_CD_COL_NO]))
+ if len(self.bu_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_BU_CD_COL_NO]))
+ if len(self.start_date) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_START_DATE]))
+ if len(self.end_date) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_END_DATE]))
+
+ return error_list
+
+ def check_inst_cd_exists(self) -> list[str]:
+ error_list = []
+
+ if is_not_empty(self.inst_cd) and super().is_exist_inst_cd() is False:
+ error_list.append(
+ f'{self.line_num}行目の{constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_INST_CD_COL_NO]}\
+は施設マスタに存在しないコードです。')
+ return error_list
+
+ def check_emp_cd_exists(self) -> list[str]:
+ error_list = []
+ if not self.start_date or not self.emp_cd:
+ return error_list
+
+ if super().is_exist_emp_cd(self.start_date) is True:
+ error_list.append(f'{self.line_num}行目の{constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_EMP_CD_COL_NO]}\
+は従業員マスタに存在しない もしくは 適用期間外のIDです。')
+ return error_list
+
+ def check_bu_cd_exists(self) -> list[str]:
+ error_list = []
+
+ if is_not_empty(self.bu_cd) and super().is_exist_bu_cd() is False:
+ error_list.append(f'{self.line_num}行目の{constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_BU_CD_COL_NO]}\
+はビジネスユニットマスタに存在しないコードです。')
+ return error_list
+
+ def check_existing_date(self) -> list[str]:
+ error_list = []
+ if not self.start_date or not self.end_date:
+ return error_list
+
+ (error_list, start_date_time, end_date_time) = super().check_term_date(
+ self.start_date,
+ self.end_date,
+ constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_START_DATE],
+ constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_END_DATE])
+ if len(error_list) > 0:
+ return error_list
+
+ if start_date_time > end_date_time:
+ error_list.append(f'{self.line_num}行目の{constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_START_DATE]}\
+が{constants.NEW_INST_EMP_CSV_LOGICAL_NAMES[constants.CSV_NEW_END_DATE]}よりも後の日付になっています。')
+ return error_list
+
+ def check_item_count(self) -> list[str]:
+ return super().check_csv_item_count(len(constants.NEW_INST_EMP_CSV_LOGICAL_NAMES))
+
+ def check_data_exists(self) -> list[str]:
+ error_list = []
+ if super().emp_chg_inst_count(self.start_date) > 0:
+ error_list.append(f'{self.line_num}行目の施設コード、領域コード、適用開始日がすべて同一のデータが既に登録されています。')
+
+ return error_list
+
+
+class MasterMainteChangeInstEmpCSVItem(MasterMainteCSVItem):
+ """施設担当者変更登録CSV"""
+ bu_name: str
+ org_cd: str
+ org_short_name: str
+ inst_name: str
+ explain: str
+ emp_full_name: str
+ inst_emp_start_date: str
+ inst_emp_end_date: str
+ change_end_date: str
+ comment: str
+
+ def __init__(
+ self,
+ csv_row: list[str],
+ table_name: str,
+ line_num: str,
+ mst_inst_repository: MstInstRepository,
+ emp_master_repository: EmpMasterRepository,
+ bu_master_repository: BuMasterRepository,
+ emp_chginst_repository: EmpChgInstRepository
+ ):
+ super().__init__(
+ csv_row,
+ table_name,
+ line_num,
+ mst_inst_repository,
+ emp_master_repository,
+ bu_master_repository,
+ emp_chginst_repository
+ )
+ self.bu_cd = super().get_csv_value(constants.CSV_CHANGE_BU_CD_COL_NO)
+ self.bu_name = super().get_csv_value(constants.CSV_CHANGE_BU_NAME_COL_NO)
+ self.org_cd = super().get_csv_value(constants.CSV_CHANGE_ORG_CD_COL_NO)
+ self.org_short_name = super().get_csv_value(constants.CSV_CHANGE_ORG_SHORT_NAME_COL_NO)
+ self.inst_cd = super().get_csv_value(constants.CSV_CHANGE_INST_CD_COL_NO)
+ self.inst_name = super().get_csv_value(constants.CSV_CHANGE_INST_NAME_COL_NO)
+ self.ta_cd = super().get_csv_value(constants.CSV_CHANGE_TA_CD_COL_NO)
+ self.explain = super().get_csv_value(constants.CSV_CHANGE_EXPLAIN_COL_NO)
+ self.emp_cd = super().get_csv_value(constants.CSV_CHANGE_EMP_CD_COL_NO)
+ self.emp_full_name = super().get_csv_value(constants.CSV_CHANGE_EMP_FULL_NAME_COL_NO)
+ self.inst_emp_start_date = super().get_csv_value(constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO)
+ self.inst_emp_end_date = super().get_csv_value(constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO)
+ self.change_end_date = super().get_csv_value(constants.CSV_CHANGE_CHANGE_END_DATE_COL_NO)
+ self.comment = super().get_csv_value(constants.CSV_CHANGE_COMMENT)
+
+ def csv_row_data(self) -> dict:
+ return {constants.CHANGE_INST_CSV_LOGICAL_NAMES[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.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_BU_CD_COL_NO]))
+ if len(self.inst_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_CD_COL_NO]))
+ if len(self.ta_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_TA_CD_COL_NO]))
+ if len(self.emp_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_EMP_CD_COL_NO]))
+ if len(self.inst_emp_start_date) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[
+ constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO]))
+ if len(self.inst_emp_end_date) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[
+ constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO]))
+ elif self.comment == '終了':
+ if len(self.inst_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_CD_COL_NO]))
+ if len(self.ta_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_TA_CD_COL_NO]))
+ if len(self.inst_emp_start_date) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num,
+ constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO]))
+ if len(self.change_end_date) == 0:
+ error_list.append(self.make_require_error_message(self.line_num,
+ constants.CHANGE_INST_CSV_LOGICAL_NAMES[
+ constants.CSV_CHANGE_CHANGE_END_DATE_COL_NO]))
+ elif self.comment == '担当者修正':
+ if len(self.inst_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_CD_COL_NO]))
+ if len(self.ta_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_TA_CD_COL_NO]))
+ if len(self.emp_cd) == 0:
+ error_list.append(self.make_require_error_message(
+ self.line_num, constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_EMP_CD_COL_NO]))
+ if len(self.inst_emp_start_date) == 0:
+ error_list.append(self.make_require_error_message(self.line_num,
+ constants.CHANGE_INST_CSV_LOGICAL_NAMES[
+ constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO]))
+ else:
+ error_list.append(f'{self.line_num}行目のコメントが不正です。 「追加」「終了」「担当者修正」のいずれかを入力してください。')
+ return error_list
+
+ def check_inst_cd_exists(self) -> list[str]:
+ error_list = []
+
+ if is_not_empty(self.inst_cd) and super().is_exist_inst_cd() is False:
+ error_list.append(f'{self.line_num}行目の{constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_CD_COL_NO]}\
+は施設マスタに存在しないコードです。')
+ return error_list
+
+ def check_emp_cd_exists(self) -> list[str]:
+ error_list = []
+ if not self.inst_emp_start_date or not self.emp_cd:
+ return error_list
+
+ if self.comment != '追加' and self.comment != '担当者修正':
+ return error_list
+
+ if super().is_exist_emp_cd(self.inst_emp_start_date) is True:
+ error_list.append(f'{self.line_num}行目の{constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_EMP_CD_COL_NO]}\
+は従業員マスタに存在しない もしくは 適用期間外のIDです。')
+ return error_list
+
+ def check_bu_cd_exists(self) -> list[str]:
+ error_list = []
+
+ if is_not_empty(self.bu_cd) and self.comment == '追加'\
+ and super().is_exist_bu_cd() is False:
+ error_list.append(f'{self.line_num}行目の{constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_BU_CD_COL_NO]}\
+はビジネスユニットマスタに存在しないコードです。')
+ return error_list
+
+ def check_existing_date(self) -> list[str]:
+ error_list = []
+ start_date = self.inst_emp_start_date
+ if self.comment == '追加' or self.comment == '終了':
+ if self.comment == '追加':
+ end_date = self.inst_emp_end_date
+ end_date_col_name = constants.CHANGE_INST_CSV_LOGICAL_NAMES[
+ constants.CSV_CHANGE_INST_EMP_END_DATE_COL_NO]
+ compare_error_message = f'\
+{constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO]}が\
+{end_date_col_name}よりも後の日付になっています。'
+ else:
+ end_date = self.change_end_date
+ end_date_col_name = constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_CHANGE_END_DATE_COL_NO]
+ compare_error_message = f'\
+{constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO]}が\
+{end_date_col_name}よりも後の日付になっています。'
+
+ if not start_date or not end_date:
+ return error_list
+
+ (error_list, start_date_time, end_date_time) = super().check_term_date(
+ start_date,
+ end_date,
+ constants.CHANGE_INST_CSV_LOGICAL_NAMES[constants.CSV_CHANGE_INST_EMP_START_DATE_COL_NO],
+ end_date_col_name)
+ if len(error_list) > 0:
+ return error_list
+
+ if start_date_time > end_date_time:
+ error_list.append(f'{self.line_num}行目の{compare_error_message}')
+ return error_list
+
+ def check_item_count(self) -> list[str]:
+ return super().check_csv_item_count(len(constants.CHANGE_INST_CSV_LOGICAL_NAMES))
+
+ 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(f'{self.line_num}行目の施設コード、領域コード、施設担当_開始日がすべて同一のデータが既に登録されています。')
+
+ elif (self.comment == '終了' or self.comment == '担当者修正') and emp_chg_inst_count == 0:
+ error_list.append(f'{self.line_num}行目の施設コード、領域コード、施設担当_開始日がすべて同一のデータが存在しないため更新できません。')
+
+ return error_list
+
+
+class MasterMainteCSVItems:
+ """施設担当者CSVをループで回すためのもの"""
+ lines: list[MasterMainteCSVItem]
+ __i: int = 0
+
+ def to_json(self):
+ # CSVをjsonに変換
+ csv_row_dict_list: list[dict] = self.to_dict()
+
+ # json作成
+ return json.dumps(csv_row_dict_list, ensure_ascii=False)
+
+ def to_dict(self):
+ return [row_item.csv_row_data() for row_item in self.lines]
+
+ 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,
+ select_function: str,
+ table_name: str,
+ mst_inst_repository: MstInstRepository,
+ emp_master_repository: EmpMasterRepository,
+ bu_master_repository: BuMasterRepository,
+ emp_chginst_repository: EmpChgInstRepository
+ ) -> None:
+ reader = csv.reader(file)
+ csv_rows = []
+ for line_num, row in enumerate(reader, start=0):
+ if line_num == 0:
+ continue
+ csv_rows.append(self.__select_function(
+ select_function,
+ row,
+ table_name,
+ line_num,
+ mst_inst_repository,
+ emp_master_repository,
+ bu_master_repository,
+ emp_chginst_repository))
+ self.lines = csv_rows
+
+ def __select_function(self,
+ function_type: str,
+ row: list[str],
+ table_name: str,
+ line_num: int,
+ mst_inst_repository: MstInstRepository,
+ emp_master_repository: EmpMasterRepository,
+ bu_master_repository: BuMasterRepository,
+ emp_chginst_repository: EmpChgInstRepository) -> MasterMainteCSVItem:
+ if function_type == 'new':
+ return MasterMainteNewInstEmpCSVItem(
+ row,
+ table_name,
+ str(line_num),
+ mst_inst_repository,
+ emp_master_repository,
+ bu_master_repository,
+ emp_chginst_repository)
+ elif function_type == 'change':
+ return MasterMainteChangeInstEmpCSVItem(
+ row,
+ table_name,
+ str(line_num),
+ mst_inst_repository,
+ emp_master_repository,
+ bu_master_repository,
+ emp_chginst_repository)
diff --git a/ecs/jskult-webapp/src/model/internal/master_mainte_emp_chg_inst_function.py b/ecs/jskult-webapp/src/model/internal/master_mainte_emp_chg_inst_function.py
new file mode 100644
index 00000000..4f4f6165
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/internal/master_mainte_emp_chg_inst_function.py
@@ -0,0 +1,165 @@
+from abc import ABCMeta, abstractmethod
+from src.repositories.emp_chg_inst_repository import EmpChgInstRepository
+from src.logging.get_logger import get_logger
+
+logger = get_logger('マスターメンテ')
+
+
+class MasterMainteEmpChgInstFunction(metaclass=ABCMeta):
+ insert_data: list[dict]
+ table_name: str
+ select_table_message: str
+ user_name: str
+ emp_chginst_repository: EmpChgInstRepository
+
+ def __init__(
+ self,
+ insert_data,
+ table_name: str,
+ select_table_message: str,
+ user_name: str,
+ emp_chginst_repository: EmpChgInstRepository
+ ):
+ self.insert_data = insert_data
+ self.table_name = table_name
+ self.select_table_message = select_table_message
+ self.user_name = user_name
+ self.emp_chginst_repository = emp_chginst_repository
+
+ def save(self):
+ error_list = []
+ try:
+ self.emp_chginst_repository.connect()
+ self.emp_chginst_repository.begin()
+ (result_message, error_list) = self.write_emp_chg_inst_table()
+ if len(error_list) > 0:
+ self.emp_chginst_repository.rollback()
+ else:
+ self.emp_chginst_repository.commit()
+ except Exception as e:
+ self.emp_chginst_repository.rollback()
+ raise e
+ finally:
+ self.emp_chginst_repository.disconnect()
+
+ return (result_message, error_list)
+
+ def add_emp_chg_inst_table(self, data, start_date, end_date):
+ self.emp_chginst_repository.insert_emp_chg_inst(
+ data['施設コード'],
+ data['領域コード'],
+ data['MUID'],
+ data['ビジネスユニットコード'],
+ start_date,
+ end_date,
+ self.user_name,
+ self.table_name)
+
+ @abstractmethod
+ def write_emp_chg_inst_table(self):
+ pass
+
+
+class NewEmpChgInstFunction(MasterMainteEmpChgInstFunction):
+
+ def __init__(
+ self,
+ insert_data_list: list[dict],
+ table_name: str,
+ select_table_message: str,
+ user_name: str,
+ emp_chginst_repository: EmpChgInstRepository
+ ):
+ super().__init__(
+ insert_data_list,
+ table_name,
+ select_table_message,
+ user_name,
+ emp_chginst_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.add_emp_chg_inst_table(data, data['適用開始日'], data['適用終了日'])
+ add_count += 1
+ except Exception as e:
+ error_list.append(f'{str(row_no)}行目がSQL実行エラーです。CSVファイルを確認してください。')
+ logger.info(f'新規施設登録時に{row_no}行目でエラーが発生しました: {e}')
+
+ result_message_list = []
+ if len(error_list) == 0:
+ 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 ChangeEmpChgInstFunction(MasterMainteEmpChgInstFunction):
+
+ def __init__(
+ self,
+ insert_data: list[dict],
+ table_name: str,
+ select_table_message: str,
+ user_name: str,
+ emp_chginst_repository: EmpChgInstRepository
+
+ ):
+ super().__init__(
+ insert_data,
+ table_name,
+ select_table_message,
+ user_name,
+ emp_chginst_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.add_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_emp_chg_inst(data)
+ modify_count += 1
+ except Exception as e:
+ error_list.append(f'{str(row_no)}行目がSQL実行エラーです。CSVファイルを確認してください。')
+ logger.info(f'施設担当者変更時に{row_no}行目でエラーが発生しました: {e}')
+
+ result_message_list = []
+ if len(error_list) == 0:
+ 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_chginst_repository.end_emp_chg_inst(
+ data['施設コード'],
+ data['領域コード'],
+ data['施設担当_開始日'],
+ data['終了日の変更'],
+ self.user_name,
+ self.table_name)
+
+ def __modify_emp_chg_inst(self, data: dict):
+ self.emp_chginst_repository.modify_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_csvdl.py b/ecs/jskult-webapp/src/model/request/master_mainte_csvdl.py
new file mode 100644
index 00000000..4155fa73
--- /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_from: Optional[str]
+ adapt_apply_date_from: 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_from: 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_from,
+ 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_from: 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_from = ''
+ if is_not_empty(ctrl_apply_date_from):
+ adapt_apply_date_from = ctrl_apply_date_from.replace('/', '')
+ else:
+ ctrl_apply_date_from = ''
+
+ 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('/', '-') + ' 00:00:00'
+ else:
+ ctrl_create_date_from = ''
+ if is_not_empty(ctrl_create_date_to):
+ adapt_create_date_to = ctrl_create_date_to.replace('/', '-') + ' 23:59:59'
+ 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('/', '-') + ' 00:00:00'
+ else:
+ ctrl_update_date_from = ''
+ if is_not_empty(ctrl_update_date_to):
+ adapt_update_date_to = ctrl_update_date_to.replace('/', '-') + ' 23:59:59'
+ 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_from=ctrl_apply_date_from,
+ adapt_apply_date_from=adapt_apply_date_from,
+ 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
new file mode 100644
index 00000000..2f24bd8b
--- /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_download_view_model.py b/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py
index 220294ba..a0bd7f3d 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,31 @@
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_from: 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)
+
+ def is_download_file_url_empty(self):
+ return not is_not_empty(self.download_file_url)
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..b2ab8051 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,49 @@
+from typing import Optional
+
from pydantic import BaseModel
+from src.system_var import constants
class InstEmpCsvUploadViewModel(BaseModel):
subtitle: str = '施設担当者データCSVアップロード'
+ is_verified: Optional[bool]
+ is_insert: Optional[bool]
+ error_message_list: Optional[list[str]]
+ select_function: Optional[str]
+ select_table: Optional[str]
+ csv_file_name: Optional[str]
+ csv_upload_list: Optional[list[dict]]
+ json_upload_data: Optional[str]
+ result_message_list: Optional[list[str]]
+ select_function_message: Optional[str]
+
+ 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_message_list_empty(self):
+ return self.error_message_list is None or len(self.error_message_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_LOGICAL_NAMES
+ if self.select_function == 'change':
+ return constants.CHANGE_INST_CSV_LOGICAL_NAMES
+ return []
+
+ def __real_table(self):
+ return constants.CSV_REAL_TABLE_NAME
+
+ def __dummy_table(self):
+ return constants.CSV_CHANGE_TABLE_NAME
diff --git a/ecs/jskult-webapp/src/model/view/table_override_view_model.py b/ecs/jskult-webapp/src/model/view/table_override_view_model.py
index e03b1fd0..d97a1928 100644
--- a/ecs/jskult-webapp/src/model/view/table_override_view_model.py
+++ b/ecs/jskult-webapp/src/model/view/table_override_view_model.py
@@ -1,5 +1,8 @@
from pydantic import BaseModel
+from typing import Optional
class TableOverrideViewModel(BaseModel):
subtitle: str = 'テーブル上書きコピー'
+
+ is_override: Optional[bool] = False
diff --git a/ecs/jskult-webapp/src/repositories/bu_master_cd_repository.py b/ecs/jskult-webapp/src/repositories/bu_master_cd_repository.py
new file mode 100644
index 00000000..36992192
--- /dev/null
+++ b/ecs/jskult-webapp/src/repositories/bu_master_cd_repository.py
@@ -0,0 +1,32 @@
+from src.repositories.base_repository import BaseRepository
+from src.model.db.master_mente_count import MasterMenteCountModel
+from src.logging.get_logger import get_logger
+
+logger = get_logger('ビジネスユニットマスタ')
+
+
+class BuMasterRepository(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:
+ logger.exception(f"DB Error : Exception={e.args}")
+ raise e
+ finally:
+ self._database.disconnect()
diff --git a/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py b/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py
new file mode 100644
index 00000000..404d7bca
--- /dev/null
+++ b/ecs/jskult-webapp/src/repositories/emp_chg_inst_repository.py
@@ -0,0 +1,300 @@
+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('従業員担当施設マスタ')
+
+
+class EmpChgInstRepository(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, 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': create_user_name
+ })
+ except Exception as e:
+ logger.exception(f'DB Error : Exception={e.args}')
+ raise e
+
+ UPDATE_END_DATE_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_END_DATE_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:
+ logger.exception(f'DB Error : Exception={e.args}')
+ raise e
+
+ UPDATE_EMP_CD_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_emp_chg_inst(self, inst_cd, ta_cd, start_date, emp_cd, update_user_name, table_name):
+ try:
+ query = self.UPDATE_EMP_CD_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:
+ logger.exception(f'DB Error : Exception={e.args}')
+ raise e
+
+ 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:
+ logger.exception(f'DB Error : Exception={e.args}')
+ 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()
+ 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= {df.shape[0]}')
+ return df
+ 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_from):
+ where_clauses.append(SQLCondition('eci.start_date',
+ condition.LE,
+ 'adapt_apply_date_from'))
+ where_clauses.append(SQLCondition('eci.end_date',
+ condition.GE,
+ 'adapt_apply_date_from'))
+
+ # 適用開始日(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
+
+ DELETE_SQL = "DELETE FROM emp_chg_inst_wrk"
+
+ def delete_dummy_table(self):
+ try:
+ query = self.DELETE_SQL
+ self._database.execute(query)
+ except Exception as e:
+ logger.exception(f'DB Error : Exception={e.args}')
+ raise e
+
+ COPY_TABLE_SQL = "INSERT INTO emp_chg_inst_wrk SELECT * FROM emp_chg_inst"
+
+ def copy_real_to_dummy(self):
+ try:
+ query = self.COPY_TABLE_SQL
+ self._database.execute(query)
+ except Exception as e:
+ logger.exception(f'DB Error : Exception={e.args}')
+ raise e
diff --git a/ecs/jskult-webapp/src/repositories/emp_master_repository.py b/ecs/jskult-webapp/src/repositories/emp_master_repository.py
new file mode 100644
index 00000000..8c278177
--- /dev/null
+++ b/ecs/jskult-webapp/src/repositories/emp_master_repository.py
@@ -0,0 +1,34 @@
+from src.repositories.base_repository import BaseRepository
+from src.model.db.master_mente_count import MasterMenteCountModel
+from src.logging.get_logger import get_logger
+
+logger = get_logger('従業員マスタ')
+
+
+class EmpMasterRepository(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_work_date, '%Y%m%d')
+ AND str_to_date(:start_work_date, '%Y%m%d') <= str_to_date(emp.end_date ,'%Y%m%d')
+ """
+
+ def fetch_count(self, emp_cd, start_work_date) -> MasterMenteCountModel:
+ try:
+ self._database.connect()
+ query = self.FETCH_COUNT_SQL
+ result = self._database.execute_select(query, {'emp_cd': emp_cd, 'start_work_date': start_work_date})
+ models = [MasterMenteCountModel(**r) for r in result]
+ if len(models) == 0:
+ return 0
+ return models[0].count
+ except Exception as e:
+ logger.exception(f"DB Error : Exception={e.args}")
+ raise e
+ finally:
+ self._database.disconnect()
diff --git a/ecs/jskult-webapp/src/repositories/mst_inst_repository.py b/ecs/jskult-webapp/src/repositories/mst_inst_repository.py
new file mode 100644
index 00000000..9c92599c
--- /dev/null
+++ b/ecs/jskult-webapp/src/repositories/mst_inst_repository.py
@@ -0,0 +1,32 @@
+from src.repositories.base_repository import BaseRepository
+from src.model.db.master_mente_count import MasterMenteCountModel
+from src.logging.get_logger import get_logger
+
+logger = get_logger('メルク施設マスタ')
+
+
+class MstInstRepository(BaseRepository):
+
+ FETCH_COUNT_SQL = """\
+ SELECT
+ COUNT(*) AS count
+ FROM
+ src05.mst_inst
+ WHERE
+ mst_inst.inst_cd = :inst_cd
+ """
+
+ def fetch_count(self, inst_cd) -> MasterMenteCountModel:
+ try:
+ self._database.connect()
+ query = self.FETCH_COUNT_SQL
+ result = self._database.execute_select(query, {'inst_cd': inst_cd})
+ models = [MasterMenteCountModel(**r) for r in result]
+ if len(models) == 0:
+ return 0
+ return models[0].count
+ except Exception as e:
+ logger.exception(f"DB Error : Exception={e.args}")
+ raise e
+ finally:
+ self._database.disconnect()
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..e9620eda
--- /dev/null
+++ b/ecs/jskult-webapp/src/services/master_mainte_service.py
@@ -0,0 +1,262 @@
+import os
+import json
+import html
+import csv
+
+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
+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.model.internal.master_mainte_csv import MasterMainteCSVItems
+from src.model.internal.master_mainte_emp_chg_inst_function import NewEmpChgInstFunction
+from src.model.internal.master_mainte_emp_chg_inst_function import ChangeEmpChgInstFunction
+from src.model.view.inst_emp_csv_upload_view_model import InstEmpCsvUploadViewModel
+from src.model.view.table_override_view_model import TableOverrideViewModel
+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
+
+
+logger = get_logger('マスターメンテ')
+
+
+class MasterMainteService(BaseService):
+ REPOSITORIES = {
+ 'mst_inst_repository': MstInstRepository,
+ 'emp_master_repository': EmpMasterRepository,
+ 'bu_master_repository': BuMasterRepository,
+ '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)
+ self.mst_inst_repository = repositories['mst_inst_repository']
+ 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,
+ csv_file_name: str,
+ csv_upload_form: MasterMainteCsvUpModel) -> InstEmpCsvUploadViewModel:
+
+ if csv_upload_form.select_function != 'new' and csv_upload_form.select_function != 'change':
+ raise Exception(f'機能の選択値が不正です: {csv_upload_form.select_function}')
+ if csv_upload_form.select_table != 'dummy' and csv_upload_form.select_table != 'real':
+ raise Exception(f'登録テーブルの選択値が不正です: {csv_upload_form.select_table}')
+
+ (table_name, selected_table_msg) = self.__choose_target_table(csv_upload_form.select_table)
+
+ csv_items = MasterMainteCSVItems(
+ file,
+ csv_upload_form.select_function,
+ table_name,
+ self.mst_inst_repository,
+ self.emp_master_repository,
+ self.bu_master_repository,
+ self.emp_chginst_repository
+ )
+
+ error_message_list = []
+ # CSVファイル0件(ヘッダ行のみ)チェック
+ if len(csv_items.lines) == 0:
+ error_message_list.append('選択されたCSVファイルの2行目以降に値が記入されておりません。')
+ else:
+ for row_item in csv_items:
+ error_message_list.extend([data for data in row_item.validate()])
+
+ csv_upload_list = []
+ json_upload_data = ''
+ if len(error_message_list) == 0:
+ csv_upload_list: list[dict] = csv_items.to_dict()
+ # json作成
+ json_upload_data = csv_items.to_json()
+
+ mainte_csv_up = InstEmpCsvUploadViewModel(
+ is_verified=True,
+ error_message_list=error_message_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,
+ select_function_message=self.__make_dialog_confirm_message(
+ csv_upload_form.select_function,
+ selected_table_msg)
+ )
+ return mainte_csv_up
+
+ def prepare_mainte_new_inst_view(self,
+ user_name: str,
+ csv_upload_form: MasterMainteCsvUpModel) -> InstEmpCsvUploadViewModel:
+
+ (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))
+
+ if csv_upload_form.select_function == 'new':
+ emp_chg_inst = NewEmpChgInstFunction(
+ csv_data_list,
+ table_name,
+ selected_table_msg,
+ user_name,
+ self.emp_chginst_repository)
+ elif csv_upload_form.select_function == 'change':
+ emp_chg_inst = ChangeEmpChgInstFunction(
+ csv_data_list,
+ table_name,
+ selected_table_msg,
+ user_name,
+ self.emp_chginst_repository)
+ else:
+ raise Exception(f'機能の選択値が不正です: {csv_upload_form.select_function}')
+
+ (result_message_list, raw_error_list) = emp_chg_inst.save()
+
+ error_message_list = []
+ error_message_list.extend(raw_error_list)
+
+ mainte_csv_up = InstEmpCsvUploadViewModel(
+ is_insert=True,
+ result_message_list=result_message_list,
+ error_message_list=error_message_list
+ )
+ return mainte_csv_up
+
+ def copy_data_real_to_dummy(self) -> TableOverrideViewModel:
+ try:
+ self.emp_chginst_repository.connect()
+ self.emp_chginst_repository.begin()
+ self.emp_chginst_repository.delete_dummy_table()
+ self.emp_chginst_repository.copy_real_to_dummy()
+ self.emp_chginst_repository.commit()
+ except Exception as e:
+ self.emp_chginst_repository.rollback()
+ raise e
+ 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.__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に書き込み
+ 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, encoding="utf-8_sig", quoting=csv.QUOTE_ALL, index=False, header=False)
+
+ return output_file_path
+
+ def upload_emp_chg_inst_data_file(self, df: pd.DataFrame, user_id: str, select_table: str) -> tuple[str, str]:
+ if df.shape[0] == 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.shape[0]}件をCSVファイルに出力しました'
+ else:
+ result_msg = f'本番テーブルのデータ{df.shape[0]}件を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 __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
+ elif select_table == 'real':
+ table_name = 'src05.emp_chg_inst'
+ selected_table_msg = constants.CSV_REAL_TABLE_NAME
+ else:
+ raise Exception(f'登録テーブルの選択値が不正です: {select_table}')
+ return (table_name, selected_table_msg)
+
+ def __make_dialog_confirm_message(self, select_function: str, selected_table_msg: str) -> str:
+ select_function_msg = '新規施設登録' if select_function == 'new' else '施設担当者変更'
+ return f'{selected_table_msg}に{select_function_msg}を行いますか?'
+
+ def delete_local_file(self, local_file_path: str):
+ os.remove(local_file_path)
diff --git a/ecs/jskult-webapp/src/static/css/masterMainte.css b/ecs/jskult-webapp/src/static/css/masterMainte.css
index 3c15e03d..c6d7be7d 100644
--- a/ecs/jskult-webapp/src/static/css/masterMainte.css
+++ b/ecs/jskult-webapp/src/static/css/masterMainte.css
@@ -1,3 +1,9 @@
+/* Bootstrap 5.10以降、box-sizingのデフォルト値によってテーブルがずれるため、このページ限定的にリセット */
+/* @see https://bootstrap-guide.com/content/reboot#page-defaults */
+table {
+ box-sizing: initial;
+}
+
body{
background-color: LightCyan;
font-family : "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif;
@@ -5,6 +11,7 @@ body{
h1{
margin-left : 1%;
+ font-weight: 700;
}
@@ -23,6 +30,10 @@ h1{
width: 20%;
}
+.header_buttonSize{
+ width: 7rem;
+ font-size: initial;
+}
.buttonSize{
width: 85px;
}
@@ -45,6 +56,7 @@ h1{
padding-bottom: 1%;
border-bottom: solid 1px gray;
width: 94%;
+ border-collapse: initial;
}
.searchLabelTd{
@@ -88,7 +100,7 @@ h1{
}
/*//////////////////////////*/
-/*施設担当者データExcelアップロード*/
+/*施設担当者データCSVアップロード*/
/*//////////////////////////*/
.inputTable{
margin-left: 3%;
@@ -97,6 +109,7 @@ h1{
padding-bottom: 1%;
border-bottom: solid 1px gray;
width: 94%;
+ border-collapse: initial;
}
.inputLabelTd{
@@ -160,5 +173,6 @@ table.inputData tbody td {
margin-bottom: 2%;
border-bottom: solid 1px gray;
width: 94%;
+ border-collapse: initial;
}
diff --git a/ecs/jskult-webapp/src/static/function/businessLogicScript.js b/ecs/jskult-webapp/src/static/function/businessLogicScript.js
index 7ce3b9ba..9983067d 100644
--- a/ecs/jskult-webapp/src/static/function/businessLogicScript.js
+++ b/ecs/jskult-webapp/src/static/function/businessLogicScript.js
@@ -84,51 +84,54 @@ function selectDropDowList(id, selectedName){
function enableDatePicker() {
// カレンダーの表示を日曜日始まりに変更
flatpickr.l10ns.ja.firstDayOfWeek = 0;
- $('.date_picker').flatpickr(
- {
+
+ $(".date_picker").each(function(i, elem) {
+ const date_picker_name = elem.name;
+
+ flatpickr(elem, {
locale: 'ja', // 日本語カレンダー
allowInput: true, // 入力可能にする
- dateFormat: 'Y/m/d' // 日付のフォーマットを修正
- }
- )
+ dateFormat: "YYYY/MM/DD", // 日付のフォーマット
+ onChange(_dates, currentDateString, _picker, _data) {
+ },
+ parseDate: function(strFormat, format) {
+
+ // yyyyMMddの場合→yyyy/MM/dd
+ const datePatternMatches = strFormat.match(/^(\d{4})(\d{2})(\d{2})$/);
+ if (datePatternMatches){
+ strFormat = `${datePatternMatches[1]}/${datePatternMatches[2]}/${datePatternMatches[3]}`;
+ }
+
+ // yyyy/00/00~yyyy/00/00の場合→yyyy/01/01~yyyy/12/31
+ // yyyy/MM/00~yyyy/MM/01の場合→yyyy/MM/01~yyyy/MM/末日
+ // 開始日の場合
+ if (date_picker_name.includes('from')){
+ strFormat = strFormat.replace("/00/00", "/01/01");
+ strFormat = strFormat.replace("/00", "/01");
+ }
+ // 終了日の場合
+ else if (date_picker_name.includes('to')){
+ strFormat = strFormat.replace("/00/00", "/12/31");
+ const date = new Date(strFormat.slice(0, 4), strFormat.slice(5, 7), 0).getDate();
+ strFormat = strFormat.replace("/00", "/"+date.toString());
+ }
+ return new Date(strFormat);
+ },
+ formatDate: (date, format) => {
+ // 日付の整合性チェック、不正の場合は空表示
+ if(isNaN(date.getDate())){
+ return;
+ }
+
+ // フォーマットを設定
+ const formatted = flatpickr.formatDate(date,'Y/m/d');
+ return formatted;
+
+ }
+ })
+ });
}
-// 日付入力チェック
-// 引数:チェックするテキストボックスNo
-function autoModifyDate($this){
- // 日付フォーマットチェック
-
- if($this.value === "" ||
- (!$this.value.match(/^\d{4}\/\d{2}\/\d{2}$/) && !$this.value.match(/^\d{4}\d{2}\d{2}$/)))
- {
- $this.value = "";
- return;
- }
-
- /** @type { string }*/
- let strFormat = $this.value;;
- // yyyyMMddの場合→yyyy/MM/dd
- const datePatternMatches = strFormat.match(/^(\d{4})(\d{2})(\d{2})$/);
- if (datePatternMatches){
- strFormat = `${datePatternMatches[1]}/${datePatternMatches[2]}/${datePatternMatches[3]}`;
- }
- // yyyy/00/00~yyyy/00/00の場合→yyyy/01/01~yyyy/12/31
- // yyyy/MM/00~yyyy/MM/01の場合→yyyy/MM/01~yyyy/MM/末日
- // 開始日の場合
- if ($this.name.includes('from')){
- strFormat = strFormat.replace("00/00", "01/01");
- strFormat = strFormat.replace("00", "01");
- }
- // 終了日の場合
- else if ($this.name.includes('to')){
- strFormat = strFormat.replace("00/00", "12/31");
- const date = new Date(strFormat.slice(0, 4), strFormat.slice(5, 7), 0).getDate();
- strFormat = strFormat.replace("00", date.toString());
- }
- $this.value = strFormat;
-}
-
-
// 前のスペースを許さない入力チェック
function checkSpaceForm($this)
{
@@ -179,3 +182,66 @@ function allOff(){
$(".selected").prop("checked", false);
$(".send").prop('disabled',true);
}
+
+// 検索結果のところのボタンをチェックが1個でも付いたら押せるようにして、チェックがなければ押せないようにする関数
+// 条件:チェックボックスのクラス名に"selected"というのがついていること
+// 条件:ボタンにクラス名 send がついていること
+function resultBtDisablead(){
+ var cnt1 = $('.checkNum input:checkbox:checked').length;
+ console.log(cnt1);
+ if(cnt1 == 0) {
+ $(".send").prop('disabled',true);
+ }
+ else {
+ $(".send").prop('disabled',false);
+ }
+}
+
+// 数字-以外を許さない入力チェック
+function checkNumberForm($this)
+{
+ 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;
+}
+
+// メニューへボタンの関数
+// 機能概要:マスターメンテメニュー画面に遷移する
+function backToMainteMenu(){
+ sessionStorage.clear();
+ location.href = "/masterMainte/masterMainteMenu";
+}
+
+// 確認ダイアログ
+function confirmDialog(strMesssage) {
+ var result = confirm(strMesssage);
+ return result;
+}
+
+function formInsertBtDisabled(){
+ var validFlg = false;
+ if(document.getElementById("csvFile").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 064d135b..a50d498e 100644
--- a/ecs/jskult-webapp/src/system_var/constants.py
+++ b/ecs/jskult-webapp/src/system_var/constants.py
@@ -132,3 +132,123 @@ LOGOUT_REASON_MESSAGE_MAP = {
LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。
再度Loginするか、
管理者にお問い合わせください。',
LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。
再度Loginするか、
管理者に問い合わせてください。'
}
+
+# 新規施設担当者登録CSV(マスターメンテ)
+NEW_INST_EMP_CSV_LOGICAL_NAMES = [
+ '施設コード',
+ '施設名',
+ '領域コード',
+ 'MUID',
+ '担当者名(姓)',
+ '担当者名(名)',
+ 'ビジネスユニットコード',
+ '適用開始日',
+ '適用終了日'
+]
+# 施設コードの列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(マスターメンテ)
+CHANGE_INST_CSV_LOGICAL_NAMES = [
+ 'ビジネスユニットコード',
+ 'ビジネスユニット名',
+ '組織コード',
+ '組織名略称',
+ '施設コード',
+ '施設名',
+ '領域コード',
+ '説明',
+ 'MUID',
+ '担当者名',
+ '施設担当_開始日',
+ '施設担当_終了日',
+ '終了日の変更',
+ 'コメント'
+]
+# ビジネスユニットコードの列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アップロードテーブル名(マスターメンテ)
+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'
+
+# CSVアップロードの制限サイズ=100MB
+MENTE_CSV_UPLOAD_MAX_FILE_SIZE_BYTE = 104857600
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 7e84fd4c..d8ac4d5b 100644
--- a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html
+++ b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html
@@ -1,12 +1,187 @@
- {% with subtitle = view.subtitle %}
+ {% with subtitle = mainte_csv_dl.subtitle %}
{% include '_header.html' %}
{% endwith %}
+
+
+
+
+
- 施設担当者データCSVダウンロード
+
+
+
+
+
+
+
+ {% 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 %}
+
+
diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvUL.html b/ecs/jskult-webapp/src/templates/instEmpCsvUL.html
index 9ec84207..2cf5770f 100644
--- a/ecs/jskult-webapp/src/templates/instEmpCsvUL.html
+++ b/ecs/jskult-webapp/src/templates/instEmpCsvUL.html
@@ -1,13 +1,207 @@
- {% with subtitle = view.subtitle %}
+ {% with subtitle = mainte_csv_up.subtitle %}
{% include '_header.html' %}
{% endwith %}
-
+
+
+
- 施設担当者データCSVアップロード
+
+
+
+
+
+
+
+
+
+ {% if not mainte_csv_up.is_error_message_list_empty() %}
+
+ {% elif mainte_csv_up.is_verified and mainte_csv_up.is_error_message_list_empty() %}
+
+
件数:{{mainte_csv_up.csv_data_count()}}件
+
+
+
+ {% elif mainte_csv_up.is_insert %}
+
+ {% endif %}
+
diff --git a/ecs/jskult-webapp/src/templates/masterMainteMenu.html b/ecs/jskult-webapp/src/templates/masterMainteMenu.html
index 957279fa..0abc4ec3 100644
--- a/ecs/jskult-webapp/src/templates/masterMainteMenu.html
+++ b/ecs/jskult-webapp/src/templates/masterMainteMenu.html
@@ -9,7 +9,7 @@
MeDaCA
マスターメンテメニュー
-
+
施設担当者データCSVアップロード
diff --git a/ecs/jskult-webapp/src/templates/tableOverride.html b/ecs/jskult-webapp/src/templates/tableOverride.html
index e473b469..30fac4ea 100644
--- a/ecs/jskult-webapp/src/templates/tableOverride.html
+++ b/ecs/jskult-webapp/src/templates/tableOverride.html
@@ -1,12 +1,61 @@
- {% with subtitle = view.subtitle %}
+ {% with subtitle = table_override.subtitle %}
{% include '_header.html' %}
{% endwith %}
+
+
+
-
テーブル上書きコピー
+
+
+
+
+
+
+ {% if table_override.is_override %}
+
+
ダミー従業員担当施設マスタのデータを本番従業員担当施設マスタのデータで上書きしました
+
+ {% endif %}
+
+
データ上書き中...
しばらくお待ち下さい。
+
+