diff --git a/ecs/jskult-webapp/src/controller/master_mainte.py b/ecs/jskult-webapp/src/controller/master_mainte.py
new file mode 100644
index 00000000..ea972ad6
--- /dev/null
+++ b/ecs/jskult-webapp/src/controller/master_mainte.py
@@ -0,0 +1,185 @@
+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.model.internal.session import UserSession
+from src.model.view.inst_emp_csv_download_view_model import \
+ InstEmpCsvDownloadViewModel
+from src.model.view.inst_emp_csv_upload_view_model import \
+ InstEmpCsvUploadViewModel
+from src.model.view.master_mainte_menu_view_model import \
+ MasterMainteMenuViewModel
+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.session_service import set_session
+from src.system_var import constants
+from src.templates import templates
+
+router = APIRouter()
+router.route_class = AuthenticatedRoute
+
+#########################
+# Views #
+#########################
+
+
+@router.get('/masterMainteMenu', response_class=HTMLResponse)
+def menu_view(
+ request: Request,
+ 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)
+
+ # 画面表示用のモデル
+ menu = MasterMainteMenuViewModel()
+ # セッション書き換え
+ 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(
+ 'masterMainteMenu.html',
+ {
+ 'request': request,
+ 'menu': menu
+ },
+ headers={'session_key': session.session_key}
+ )
+ return templates_response
+
+
+@router.get('/instEmpCsvUL', response_class=HTMLResponse)
+def inst_emp_csv_upload_view(
+ request: Request,
+ 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)
+
+ # 画面表示用のモデル
+ view_model = InstEmpCsvUploadViewModel()
+ # セッション書き換え
+ 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,
+ 'view': view_model
+ },
+ 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))
+):
+ 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)
+
+ # 画面表示用のモデル
+ view_model = InstEmpCsvDownloadViewModel()
+ # セッション書き換え
+ 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,
+ 'view': view_model
+ },
+ headers={'session_key': session.session_key}
+ )
+ return templates_response
+
+
+@router.get('/tableOverride', response_class=HTMLResponse)
+def table_override_view(
+ request: Request,
+ 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)
+
+ # 画面表示用のモデル
+ view_model = TableOverrideViewModel()
+ # セッション書き換え
+ 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,
+ 'view': view_model
+ },
+ headers={'session_key': session.session_key}
+ )
+ return templates_response
diff --git a/ecs/jskult-webapp/src/controller/menu.py b/ecs/jskult-webapp/src/controller/menu.py
index 61a1a3a0..96826fce 100644
--- a/ecs/jskult-webapp/src/controller/menu.py
+++ b/ecs/jskult-webapp/src/controller/menu.py
@@ -32,6 +32,7 @@ def menu_view(
hdke_tbl_record = batch_status_service.hdke_table_record
batch_status = hdke_tbl_record.bch_actf
+ dump_status = hdke_tbl_record.dump_sts_kbn
user = UserViewModel(
doc_flg=session.doc_flg,
inst_flg=session.inst_flg,
@@ -40,6 +41,7 @@ def menu_view(
)
menu = MenuViewModel(
batch_status=batch_status,
+ dump_status=dump_status,
user_model=user
)
# セッション書き換え
diff --git a/ecs/jskult-webapp/src/main.py b/ecs/jskult-webapp/src/main.py
index 2aca351c..8717c7cb 100644
--- a/ecs/jskult-webapp/src/main.py
+++ b/ecs/jskult-webapp/src/main.py
@@ -6,7 +6,7 @@ from starlette import status
import src.static as static
from src.controller import (bio, bio_download, healthcheck, login, logout,
- menu, root, ultmarc)
+ master_mainte, menu, root, ultmarc)
from src.controller.sample_send_file import router as sample_router
from src.core import tasks
from src.error.exception_handler import http_exception_handler
@@ -31,6 +31,8 @@ app.include_router(ultmarc.router, prefix='/ultmarc')
# 生物由来のダウンロード用APIルーター。
# クライアントから非同期呼出しされるため、共通ルーターとは異なる扱いとする。
app.include_router(bio_download.router, prefix='/bio')
+# マスタメンテ
+app.include_router(master_mainte.router, prefix='/masterMainte')
# ヘルスチェック用のルーター
app.include_router(healthcheck.router, prefix='/healthcheck')
diff --git a/ecs/jskult-webapp/src/model/db/hdke_tbl.py b/ecs/jskult-webapp/src/model/db/hdke_tbl.py
index 944581d5..9655c6c1 100644
--- a/ecs/jskult-webapp/src/model/db/hdke_tbl.py
+++ b/ecs/jskult-webapp/src/model/db/hdke_tbl.py
@@ -5,3 +5,4 @@ from src.model.db.base_db_model import BaseDBModel
class HdkeTblModel(BaseDBModel):
bch_actf: Optional[str]
+ dump_sts_kbn: Optional[str]
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
new file mode 100644
index 00000000..220294ba
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/view/inst_emp_csv_download_view_model.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+
+class InstEmpCsvDownloadViewModel(BaseModel):
+ subtitle: str = '施設担当者データCSVダウンロード'
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
new file mode 100644
index 00000000..64bde407
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/view/inst_emp_csv_upload_view_model.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+
+class InstEmpCsvUploadViewModel(BaseModel):
+ subtitle: str = '施設担当者データCSVアップロード'
diff --git a/ecs/jskult-webapp/src/model/view/master_mainte_menu_view_model.py b/ecs/jskult-webapp/src/model/view/master_mainte_menu_view_model.py
new file mode 100644
index 00000000..2b1629b1
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/view/master_mainte_menu_view_model.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+
+class MasterMainteMenuViewModel(BaseModel):
+ subtitle: str = 'MeDaCA マスターメンテメニュー'
diff --git a/ecs/jskult-webapp/src/model/view/menu_view_model.py b/ecs/jskult-webapp/src/model/view/menu_view_model.py
index 647bdec9..7a7970d2 100644
--- a/ecs/jskult-webapp/src/model/view/menu_view_model.py
+++ b/ecs/jskult-webapp/src/model/view/menu_view_model.py
@@ -3,15 +3,20 @@ from typing import Optional
from pydantic import BaseModel
from src.model.view.user_view_model import UserViewModel
+from src.system_var import constants
class MenuViewModel(BaseModel):
subtitle: str = 'MeDaCA 機能メニュー'
batch_status: Optional[str]
+ dump_status: Optional[str]
user_model: UserViewModel
def is_batch_processing(self):
- return self.batch_status == '1'
+ return self.batch_status == constants.BATCH_STATUS_PROCESSING
+
+ def is_backup_processing(self):
+ return self.dump_status != constants.DUMP_STATUS_UNPROCESSED
def is_available_ult_doctor_menu(self):
return self.user_model.has_ult_doctor_permission()
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
new file mode 100644
index 00000000..e03b1fd0
--- /dev/null
+++ b/ecs/jskult-webapp/src/model/view/table_override_view_model.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+
+class TableOverrideViewModel(BaseModel):
+ subtitle: str = 'テーブル上書きコピー'
diff --git a/ecs/jskult-webapp/src/model/view/user_view_model.py b/ecs/jskult-webapp/src/model/view/user_view_model.py
index 55f1528a..5b523b4c 100644
--- a/ecs/jskult-webapp/src/model/view/user_view_model.py
+++ b/ecs/jskult-webapp/src/model/view/user_view_model.py
@@ -4,10 +4,10 @@ from pydantic import BaseModel
class UserViewModel(BaseModel):
- bio_flg: str # AUTH_FLG1
- doc_flg: str # AUTH_FLG2
- inst_flg: str # AUTH_FLG3
- master_mainte_flg: str # AUTH_FLG4
+ bio_flg: Optional[str] # AUTH_FLG1
+ doc_flg: Optional[str] # AUTH_FLG2
+ inst_flg: Optional[str] # AUTH_FLG3
+ master_mainte_flg: Optional[str] # AUTH_FLG4
user_flg: Optional[str] # MNTUSER_FLG
def has_ult_doctor_permission(self):
diff --git a/ecs/jskult-webapp/src/repositories/hdke_tbl_repository.py b/ecs/jskult-webapp/src/repositories/hdke_tbl_repository.py
index 46f5bfcc..967fbbe1 100644
--- a/ecs/jskult-webapp/src/repositories/hdke_tbl_repository.py
+++ b/ecs/jskult-webapp/src/repositories/hdke_tbl_repository.py
@@ -6,7 +6,7 @@ logger = get_logger('日付テーブル取得')
class HdkeTblRepository(BaseRepository):
- FETCH_SQL = "SELECT bch_actf FROM src05.hdke_tbl"
+ FETCH_SQL = "SELECT bch_actf, dump_sts_kbn FROM src05.hdke_tbl"
def fetch_all(self) -> list[HdkeTblModel]:
try:
diff --git a/ecs/jskult-webapp/src/services/batch_status_service.py b/ecs/jskult-webapp/src/services/batch_status_service.py
index c9f6c6a7..ffb57af0 100644
--- a/ecs/jskult-webapp/src/services/batch_status_service.py
+++ b/ecs/jskult-webapp/src/services/batch_status_service.py
@@ -4,6 +4,7 @@ from src.model.db.hdke_tbl import HdkeTblModel
from src.repositories.base_repository import BaseRepository
from src.repositories.hdke_tbl_repository import HdkeTblRepository
from src.services.base_service import BaseService
+from src.system_var import constants
class BatchStatusService(BaseService):
@@ -25,17 +26,30 @@ class BatchStatusService(BaseService):
@property
def hdke_table_record(self) -> HdkeTblModel:
+ """日付テーブルを取得する"""
+
# 日付マスタのレコードがあることを確認
self.__assert_record_exists()
# 日付テーブルのレコードは必ず1件
return self.__hdke_table_record[0]
def is_batch_processing(self):
+ """バッチ処理中かどうかを判定する"""
+
# 日付マスタのレコードがあることを確認
self.__assert_record_exists()
- return self.hdke_table_record.bch_actf == '1' # TODO: 定数化する
+ return self.hdke_table_record.bch_actf == constants.BATCH_STATUS_PROCESSING
+
+ def is_dump_processing(self):
+ """dump処理処理中かどうかを判定する"""
+
+ # 日付マスタのレコードがあることを確認
+ self.__assert_record_exists()
+ return self.hdke_table_record.dump_sts_kbn != constants.DUMP_STATUS_UNPROCESSED
def __assert_record_exists(self):
+ """日付テーブルが有ることを保証する"""
+
# 日付マスタのレコードがない場合は例外とする
if len(self.__hdke_table_record) == 0:
raise DBException('日付テーブルのレコードが存在しません')
diff --git a/ecs/jskult-webapp/src/static/css/masterMainte.css b/ecs/jskult-webapp/src/static/css/masterMainte.css
new file mode 100644
index 00000000..a59c1681
--- /dev/null
+++ b/ecs/jskult-webapp/src/static/css/masterMainte.css
@@ -0,0 +1,164 @@
+body{
+ background-color: LightCyan;
+ font-family : "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif;
+}
+
+h1{
+ margin-left : 1%;
+}
+
+
+/*ヘッダー*/
+.headerTable{
+ width: 100%;
+}
+
+.headerTdLeft{
+ width: 80%;
+}
+
+.headerTdRight{
+ text-align: right;
+ padding-right: 2%;
+ width: 20%;
+}
+
+.buttonSize{
+ width: 85px;
+}
+
+/*////////////////////////*/
+/*施設担当者データCSVダウンロード*/
+/*////////////////////////*/
+.searchColumnTd{
+ width: 14%;
+}
+
+.searchTextboxTd{
+ width: 18%;
+}
+
+.searchTable{
+ margin-left: 3%;
+ margin-right: 3%;
+ margin-bottom: 1%;
+ padding-bottom: 1%;
+ border-bottom: solid 1px gray;
+ width: 94%;
+}
+
+.searchLabelTd{
+ text-align: right;
+ width: 10%;
+
+}
+
+.searchInputTd{
+ width: 19%;
+}
+
+.searchTextbox{
+ width: 90%;
+ margin-left: 2.5%;
+ margin-right: 2.5%;
+ margin-top: 0.8%;
+ margin-bottom: 0.8%;
+}
+
+.searchDateTextbox{
+ width: 37%;
+ margin-left: 2.5%;
+ margin-right: 2.5%;
+ margin-top: 0.8%;
+ margin-bottom: 0.8%;
+}
+
+.searchButtonTd{
+ text-align: right;
+ padding-top: 1%;
+}
+
+
+.csvOutputMessage{
+ margin-left: 3%;
+}
+
+.errorColor{
+ color: red;
+}
+
+/*//////////////////////////*/
+/*施設担当者データExcelアップロード*/
+/*//////////////////////////*/
+.inputTable{
+ margin-left: 3%;
+ margin-right: 3%;
+ margin-bottom: 1%;
+ padding-bottom: 1%;
+ border-bottom: solid 1px gray;
+ width: 94%;
+}
+
+.inputLabelTd{
+ width: 10%;
+}
+
+.inputTd{
+ width:20%;
+}
+
+.inputButtonTd{
+ width: 50%;
+ text-align: right;
+}
+
+.dataCntDisp{
+ text-align: right;
+ margin-right: 3%;
+}
+
+table.inputData {
+ font-family:arial;
+ background-color: #CDCDCD;
+ font-size: 12pt;
+ text-align: left;
+ white-space: nowrap;
+ border: 0.1px solid silver;
+ padding: 4px;
+ padding-right: 20px;
+ border-collapse: collapse;
+ margin-left: 3%;
+ width: 94%;
+}
+table.inputData tbody th {
+ color: #3D3D3D;
+ padding: 4px;
+ background-color: #e6EEEE;
+ border: 0.1px solid silver;
+ vertical-align: top;
+}
+
+table.inputData tbody td {
+ color: #3D3D3D;
+ padding: 4px;
+ background-color: #FFF;
+ border: 0.1px solid silver;
+ vertical-align: top;
+}
+
+.footerMsg{
+ margin-left: 3%;
+}
+
+
+/*//////////////////////////*/
+/*データ上書きコピー */
+/*//////////////////////////*/
+.tableOverRide{
+ margin-right: 3%;
+ margin-left: 3%;
+ margin-bottom: 2%;
+ border-bottom: solid 1px gray;
+ width: 94%;
+}
+
diff --git a/ecs/jskult-webapp/src/static/css/menuStyle.css b/ecs/jskult-webapp/src/static/css/menuStyle.css
index b1920070..3a07d9fc 100644
--- a/ecs/jskult-webapp/src/static/css/menuStyle.css
+++ b/ecs/jskult-webapp/src/static/css/menuStyle.css
@@ -37,7 +37,7 @@ body{
font-size: 160%;
}
-.notUseBioMsg{
+.notUseBioMsg,.notUseMainteMsg{
font-size: 143%;
color: red;
}
diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py
index 899c19e5..604acfe5 100644
--- a/ecs/jskult-webapp/src/system_var/constants.py
+++ b/ecs/jskult-webapp/src/system_var/constants.py
@@ -1,5 +1,10 @@
import os.path as path
+# 日付テーブル.バッチ処理ステータス:未処理
+BATCH_STATUS_PROCESSING = '1'
+# 日付テーブル.dump取得状態区分:未処理
+DUMP_STATUS_UNPROCESSED = '0'
+
BIO_TEMPORARY_FILE_DIR_PATH = path.join(path.curdir, 'src', 'data')
BIO_EXCEL_TEMPLATE_FILE_PATH = path.join(BIO_TEMPORARY_FILE_DIR_PATH, 'BioData_template.xlsx')
@@ -112,6 +117,7 @@ LOGOUT_REASON_DO_LOGOUT = 'do_logout'
LOGOUT_REASON_LOGIN_ERROR = 'login_error'
LOGOUT_REASON_BATCH_PROCESSING = 'batch_processing'
LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE = 'batch_processing_ult'
+LOGOUT_REASON_BACKUP_PROCESSING = 'dump_processing'
LOGOUT_REASON_NOT_LOGIN = 'not_login'
LOGOUT_REASON_SESSION_EXPIRED = 'session_expired'
LOGOUT_REASON_DB_ERROR = 'db_error'
@@ -122,6 +128,7 @@ LOGOUT_REASON_MESSAGE_MAP = {
LOGOUT_REASON_LOGIN_ERROR: '存在しないユーザー、
またはパスワードが違います。',
LOGOUT_REASON_BATCH_PROCESSING: '日次バッチ処理中なので、
生物由来データ参照は使用出来ません。',
LOGOUT_REASON_BATCH_PROCESSING_FOR_MAINTE: '日次バッチ処理中のため、
マスタ-メンテは使用出来ません。',
+ LOGOUT_REASON_BACKUP_PROCESSING: 'バックアップ取得を開始しました。
日次バッチ更新が終了するまでマスターメンテは使用できません',
LOGOUT_REASON_NOT_LOGIN: 'Loginしてからページにアクセスしてください。',
LOGOUT_REASON_SESSION_EXPIRED: 'セッションが切れています。
再度Loginしてください。',
LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。
再度Loginするか、
管理者にお問い合わせください。',
diff --git a/ecs/jskult-webapp/src/templates/instEmpCsvDL.html b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html
new file mode 100644
index 00000000..7e84fd4c
--- /dev/null
+++ b/ecs/jskult-webapp/src/templates/instEmpCsvDL.html
@@ -0,0 +1,12 @@
+
+
+