From f5b4628f71dfb15af8af78e59944f9bf9a2e654b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=AB=98=E6=9C=A8=E8=A6=81?=
Date: Mon, 10 Jul 2023 09:53:58 +0900
Subject: [PATCH 01/35] =?UTF-8?q?feat:=20=E3=80=90=E9=96=8B=E7=99=BA?=
=?UTF-8?q?=E3=80=91=E3=83=9E=E3=82=B9=E3=82=BF=E3=83=A1=E3=83=B3=E3=83=86?=
=?UTF-8?q?=20=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89?=
=?UTF-8?q?=E7=94=BB=E9=9D=A2(=E4=BB=AE=E4=BD=9C=E3=82=8A)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/controller/master_mainte.py | 105 +++-
.../src/model/db/master_mente_count.py | 9 +
.../src/model/internal/master_mainte_csv.py | 477 ++++++++++++++++++
.../internal/master_mainte_insert_emp_chg.py | 161 ++++++
.../src/model/request/master_mainte_csvup.py | 31 ++
.../view/inst_emp_csv_upload_view_model.py | 57 +++
.../src/model/view/mainte_csv_error_model.py | 30 ++
.../src/model/view/mainte_csv_upload_model.py | 7 +
.../mente_exist_bu_cd_repository.py | 29 ++
.../mente_exist_dummy_data_repository.py | 34 ++
.../mente_exist_emp_cd_repository.py | 32 ++
.../mente_exist_emp_chg_inst_repository.py | 32 ++
.../mente_exist_inst_cd_repository.py | 29 ++
.../mente_exist_real_data_repository.py | 34 ++
.../mente_write_emp_chg_inst_repository.py | 124 +++++
.../src/services/master_mainte_service.py | 142 ++++++
.../static/function/businessLogicScript.js | 67 ++-
ecs/jskult-webapp/src/system_var/constants.py | 107 ++++
.../src/templates/instEmpCsvDL.html | 167 +++++-
.../src/templates/instEmpCsvUL.html | 323 +++++++++++-
.../src/templates/tableOverride.html | 60 +++
21 files changed, 2050 insertions(+), 7 deletions(-)
create mode 100644 ecs/jskult-webapp/src/model/db/master_mente_count.py
create mode 100644 ecs/jskult-webapp/src/model/internal/master_mainte_csv.py
create mode 100644 ecs/jskult-webapp/src/model/internal/master_mainte_insert_emp_chg.py
create mode 100644 ecs/jskult-webapp/src/model/request/master_mainte_csvup.py
create mode 100644 ecs/jskult-webapp/src/model/view/mainte_csv_error_model.py
create mode 100644 ecs/jskult-webapp/src/model/view/mainte_csv_upload_model.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_bu_cd_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_dummy_data_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_emp_cd_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_emp_chg_inst_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_inst_cd_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_exist_real_data_repository.py
create mode 100644 ecs/jskult-webapp/src/repositories/mente_write_emp_chg_inst_repository.py
create mode 100644 ecs/jskult-webapp/src/services/master_mainte_service.py
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 %}
+
+
+
+
+
+
+
施設担当者データ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アップロード
+
+
+
+
+
+
+
+
+
+ {% if not mainte_csv_up.is_error_list_empty() %}
+
+ {% elif mainte_csv_up.is_verified and mainte_csv_up.is_error_list_empty() %}
+
+
件数:{{mainte_csv_up.csv_data_count()}}件
+
+
+
+ {% elif mainte_csv_up.is_insert %}
+
+ {% 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 %}
+
+
テーブル上書きコピー
+
+
+
+
+
+
+
+
+ |
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
データ上書き中...
しばらくお待ち下さい。
+
+
+
+
+