SVRサーバJS:確定処理後 機能レベル JAVA_SCRIPT_ENGINE/UPDATE_AFTER 2384字
コード概要 (抽出)
DB 書: ET100ET110
参照項目 (当機能): NRURIHURI (売掛振替№)IDTOKUISAKI (得意先ID)DTHURIKAE (振替日)KBZOUGEN (増減区分)KBURIHURI (振替区分)TXTEKIYO (摘要)AMHURIKAE (振替額)
//-------------------------------------------
//XDMF_LF011_0:売掛振替データの保守
//-------------------------------------------
function execXDMF_LF011_0() {
//機能IDセット(Ver3.1用)
_FUNC_ID = 'XDMF_LF011_0';
//入力情報(売掛振替№)取得
var itemBlockList = TALON.getBlockData_List(1);
var lineDataMap = itemBlockList[0]
_NRURIHURI = lineDataMap['NRURIHURI'];
//対象情報(売掛振替)取得
var itemSelectListLT010 = selectLT010(_NRURIHURI);
var lineDataMapLT010 = itemSelectListLT010[0];
var _NRSOURCE = lineDataMapLT010['NRSOURCE']
//売掛振替登録処理
// 1 : 取引先コード
// 2 : 取引日
// 3 : 増減区分
// 4 : 振替区分
// 5 : 適用
// 6 : 振替額
// 7 : ソース番号
// 8 : 参照番号(売掛振替№)
exec_urikake_ins(
lineDataMapLT010['IDTOKUISAKI']
, lineDataMapLT010['DTHURIKAE']
, lineDataMapLT010['KBZOUGEN']
, lineDataMapLT010['KBURIHURI']
, lineDataMapLT010['TXTEKIYO']
, lineDataMapLT010['AMHURIKAE']
, lineDataMapLT010['NRSOURCE']
, lineDataMapLT010['NRURIHURI']
);
//得意先の請求方式区分を取得
var itemSelectListET010 = selectET010(lineDataMapLT010['IDTOKUISAKI']);
var lineDataMapET010 = itemSelectListET010[0];
var _KBSEIKYUHOUSHIKI = lineDataMapET010['KBSEIKYUHOUSHIKI'];
if (_KBSEIKYUHOUSHIKI == '20') {
var _ZOUGENKBN = lineDataMapLT010['KBZOUGEN'];
//請求見出し[ET110]
if (_ZOUGENKBN == '0') {
//10:振替控除
var itemSelectListET100 = selectET100_NRSOURCE('10',_NRSOURCE);
} else {
//11:振替計上
var itemSelectListET100 = selectET100_NRSOURCE('11',_NRSOURCE);
}
//有効な売掛が作成された場合のみ実施
if (itemSelectListET100.length > 0) {
var lineDataMapET100 = itemSelectListET100[0];
var itemDataList = new Array();
////請求№
//itemDataList['NRSEIKYU'] = lineDataMapET100['NRURIKAKE'];
var numList = TALON.getNumberingData('XDMF_EF_SEIKYU', 1)
itemDataList['NRSEIKYU'] = numList[0];
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMapET100['IDTOKUISAKI'];
//請求日(システム日時)
itemDataList['DTSEIKYU'] = tln_com_nowdate();
//摘要(null)
itemDataList['TXTEKIYO'] = "";
//請求額
itemDataList['AMSEIKYU'] = lineDataMapET100['AMZOUGEN'];
//前回以降入金額
itemDataList['AMNYUKIN'] = "";
insertET110(itemDataList);
//更新した請求番号を現時点有効な売掛増減履歴に書き込む
TALON.update(
"UPDATE ET100 SET NRSEIKYU = '" + itemDataList['NRSEIKYU'] + "' " +
"WHERE NRURIKAKE = '" + lineDataMapET100['NRURIKAKE'] + "'"
);
}
}
}
execXDMF_LF011_0();
BODY_SQLBLOCK 1 [CARD] 513字
SELECT
LT010.NRURIHURI as NRURIHURI
,LT010.DTHURIKAE as DTHURIKAE
,LT010.IDTOKUISAKI as IDTOKUISAKI
,AT030.CDTORIHIKISAKI as CDTORIHIKISAKI
,AT030.TXKANJI as TXKANJI
,LT010.KBZOUGEN as KBZOUGEN
,LT010.KBURIHURI as KBURIHURI
,LT010.AMHURIKAE as AMHURIKAE
,LT010.TXTEKIYO as TXTEKIYO
,LT010.NRSOURCE as NRSOURCE
,LT010.MODIFY_COUNT as MODIFY_COUNT
FROM
LT010 INNER JOIN AT030
ON LT010.IDTOKUISAKI = AT030.IDTORIHIKISAKI
≣ サーバJS ライブラリASP_COMMON JavaScriptエンジン共通コード(ASP_COMMON) 3732字
/**
* 共通
*
* @version 2022/06/29
*/
//-------------------------------------------
//[共通]処理0
//-------------------------------------------
function tln_com_escape(val) {
if (val == null) return val;
var s = String(val);
return s
.replace(/\\/g, '\\\\')
.replace(/'/g, "''")
.replace(/\x00/g, '')
}
function getMapVal(map , id) {
var _rec = null;
_rec = map[id];
if (_rec == null) {
_rec = map[id.toLowerCase()];
}
return _rec;
}
function setMapVal(map , id , val) {
if ( TALON.getDbConfig().isPostgres() ) {
map[ id.toLowerCase() ] = val;
} else {
map[ id ] = val;
}
}
function chkLowercase() {
if ( TALON.getDbConfig().isPostgres() ) {
return true;
} else if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE BINARY TABLE_NAME = BINARY 'ASP_M_BOM' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal( lineDataMap , 'CNT' );
if (_CNT == 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
function editLowList(obj) {
if ( TALON.getDbConfig().isPostgres() ) {
for(var lop = 0; lop < obj.length; lop++) {
obj[lop] = obj[lop].toLowerCase();
}
}
return obj;
}
function getLanguageType() {
var sql = "" +
"SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'ASP_LANGUAGE' " +
" AND KEY_CODE = 'LANG' ";
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
var lineDataMap = itemSelectList[0];
var now_lang = getMapVal( lineDataMap , 'DSP1' );
return now_lang;
}
function getMessage(msgid, to_lang) {
//メッセージデータベース
var map = {
'MSG001' : ['処理が正常終了しました。','Process completed successfully.',' '],
'MSG002' : ['処理が異常終了しました。','Process terminated abnormally.',' '],
'MSG003' : ['他ユーザによってデータが更新されました。','Data has been updated by another user.',' '],
'MSG101' : ['不良数は0以上、製造数より小さい値で入力してください。','Please enter a value of 0 or more and less than the number of productions for "Scrap quantity".',' '],
'MSG102' : ['すでにステータスが完了の為、実績情報の変更は実施できません。','Status can not be changed because the status is already completed',' '],
'MSG103' : ['作業ステータスが「完了」もしくは「着手中」の場合、イベントは変更できません','Event can not be changed if the status is "Completed" or "Started"',' '],
'MSG501' : ['処理前チェックでエラーになりました。プロジェクトが設定されていません。データまたは設定画面の項目名がPROJECTIDになっているか確認して下さい。','An error occurred in the pre-processing check. Project has not been set. ',' '],
'MSG502' : ['処理前チェックでエラーになりました。計画月度(指定月以降を更新)を入力して下さい。または設定画面の項目名がYMPLN_YYYYMMになっているか確認して下さい。','An error occurred in the pre-processing check. Please enter the "Plan YM". ',' '],
'MSG901' : ['セットアップ・初期化処理が終了しました','Setup and initialization processes have been completed',' '],
'MSG902' : ['セットアップ・パッチ処理が終了しました','Setup and patch processes have been completed',' '],
'MSG904' : ['言語変更が終了しました','Language change processing has been completed',' ']
}
return map[msgid][to_lang];
}
function setRelationData() {
//動的表示の場合、非同期にて実施。最後にCOMMITがされるので、最初にDELETEを実施する
var deleteCount = TalonDbUtil.insert( TALON.getDbConfig() , "DELETE FROM ASP_WK_SAGYO_INFO_MAE " );
var deleteCount = TalonDbUtil.insert( TALON.getDbConfig() , "DELETE FROM ASP_WK_SAGYO_INFO_ATO " );
var insertCount = TalonDbUtil.insert( TALON.getDbConfig() , "INSERT INTO ASP_WK_SAGYO_INFO_MAE SELECT * FROM ASP_V_SAGYO_INFO_MAE" );
var insertCount = TalonDbUtil.insert( TALON.getDbConfig() , "INSERT INTO ASP_WK_SAGYO_INFO_ATO SELECT * FROM ASP_V_SAGYO_INFO_ATO" );
}
≣ サーバJS ライブラリASP_MASTER JavaScriptエンジン共通コード(ASP_MASTER) 8958字
/***************************************************************************************************
識別コード:TLN_GENERAL_JAVASCRIPT_ENGINE
検索キー :ASP_MASTER
***************************************************************************************************/
/* 製造BOMの重複チェック ------------------------------------------------------------------------ */
function fncMstBomChkExist(mapBlock){
strStepMsg = '(製造BOMの重複チェック[fncMstBomChkExist])';
var strMsg1 = '';
var strMsg2 = '';
var strMsg3 = '';
var strMsg4 = '';
var strMsg5 = '';
var strMsg6 = '';
var strSQL =
"SELECT * " +
"FROM ASP_M_BOM " +
"WHERE PROJECTID = '"+getMapVal( mapBlock , 'PROJECTID' )+"' " +
"AND ITEM_CODE = '"+getMapVal( mapBlock , 'ITEM_CODE' )+"' " +
"AND KOUTEI_NO = '"+getMapVal( mapBlock , 'KOUTEI_NO' )+"' " +
"AND SASIZU_SYUBETU = '"+getMapVal( mapBlock , 'SASIZU_SYUBETU')+"' " +
"AND SASIZU_CODE = '"+getMapVal( mapBlock , 'SASIZU_CODE' )+"' " +
"AND SIGEN_CODE = '"+getMapVal( mapBlock , 'SIGEN_CODE' )+"' ";
if( getMapVal( mapBlock , 'KOUTEI_SELECTOR' ) == null || getMapVal( mapBlock , 'KOUTEI_SELECTOR' ) == ''){
strSQL += "AND KOUTEI_SELECTOR IS NULL ";
}else{
strSQL += "AND KOUTEI_SELECTOR = '"+ getMapVal( mapBlock , 'KOUTEI_SELECTOR' )+"' ";
strMsg1 = "工程セレクタ["+ getMapVal( mapBlock , 'KOUTEI_SELECTOR' ) +"]、";
}
if( getMapVal( mapBlock , 'KOUTEI_SELECTOR_JKN' ) == null || getMapVal( mapBlock , 'KOUTEI_SELECTOR_JKN' ) == ''){
strSQL += "AND KOUTEI_SELECTOR_JKN IS NULL ";
}else{
strSQL += "AND KOUTEI_SELECTOR_JKN = '"+ getMapVal( mapBlock , 'KOUTEI_SELECTOR_JKN' ).replace(/\'/g,"''")+"' ";
strMsg2 = "工程セレクタ有効条件["+ getMapVal( mapBlock , 'KOUTEI_SELECTOR_JKN' )+"]、";
}
if( getMapVal( mapBlock , 'KOUTEI_CODE' ) == null || getMapVal( mapBlock , 'KOUTEI_CODE' ) == ''){
strSQL += "AND KOUTEI_CODE IS NULL ";
}else{
strSQL += "AND KOUTEI_CODE = '"+ getMapVal( mapBlock , 'KOUTEI_CODE' ) +"' ";
strMsg3 = "工程コード["+ getMapVal( mapBlock , 'KOUTEI_CODE' ) +"]、";
}
if( getMapVal( mapBlock , 'TASK_SELECTOR' ) == null || getMapVal( mapBlock , 'TASK_SELECTOR' ) == ''){
strSQL += "AND TASK_SELECTOR IS NULL ";
}else{
strSQL += "AND TASK_SELECTOR = '"+ getMapVal( mapBlock , 'TASK_SELECTOR' )+"' ";
strMsg4 = "タスクセレクダ["+ getMapVal( mapBlock , 'TASK_SELECTOR' ) +"]、";
}
if( getMapVal( mapBlock , 'TASK_SELECTOR_JKN' ) == null || getMapVal( mapBlock , 'TASK_SELECTOR_JKN' ) == ''){
strSQL += "AND TASK_SELECTOR_JKN IS NULL ";
}else{
strSQL += "AND TASK_SELECTOR_JKN = '"+ getMapVal( mapBlock , 'TASK_SELECTOR_JKN' ).replace(/\'/g,"''")+"' ";
strMsg5 = "タスクセレクタ有効条件["+ getMapVal( mapBlock , 'TASK_SELECTOR_JKN' )+"]、";
}
if( getMapVal( mapBlock , 'OBJECTID' ) != null && getMapVal( mapBlock , 'OBJECTID' ) != ''){
strMsg6 = "、OBJECTID["+ getMapVal( mapBlock , 'OBJECTID' )+"]";
}
TALON.getLogger().writeInfo(strFuncNm+strStepMsg+" SQL:"+strSQL);
var lstSelect = TALON.select(strSQL);
if(lstSelect.size() == 0){
TALON.setIsSuccess(true);
}else if(lstSelect.size() == 1){
if( getMapVal( mapBlock , 'OBJECTID' ) == getMapVal( lstSelect[0] , 'OBJECTID' ) ){
TALON.setIsSuccess(true);
}else{
TALON.addErrorMsg("重複しています。(PJ["+ getMapVal( mapBlock , 'PROJECTID' ) +"]、品目["+ getMapVal( mapBlock , 'ITEM_CODE' ) +"]、"+ strMsg1 + strMsg2 + "工程番号["+ getMapVal( mapBlock , 'KOUTEI_NO' ) +"]"
+ strMsg3 + strMsg4 + strMsg5 + "指図種別["+ getMapVal( mapBlock , 'SASIZU_SYUBETU' ) +"]、指図コード["+ getMapVal( mapBlock , 'SASIZU_CODE' ) +"]、品目/資源コード["+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"]"+ strMsg6 +")");
TALON.setIsSuccess(false);
}
}else{
TALON.addErrorMsg("重複しています。(PJ["+ getMapVal( mapBlock , 'PROJECTID' ) +"]、品目["+ getMapVal( mapBlock , 'ITEM_CODE' ) +"]、"+ strMsg1 + strMsg2 +"工程番号["+ getMapVal( mapBlock , 'KOUTEI_NO' ) +"]"
+ strMsg3 + strMsg4 + strMsg5 + "指図種別["+ getMapVal( mapBlock , 'SASIZU_SYUBETU' ) +"]、指図コード["+ getMapVal( mapBlock , 'SASIZU_CODE' ) +"]、品目/資源コード["+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"]"+ strMsg6 +")");
TALON.setIsSuccess(false);
}
}
/* 製造BOMの品目/資源チェック ------------------------------------------------------------------------ */
function fncMstBomChkSigen(mapBlock){
strStepMsg = '(製造BOMの品目/資源チェック[fncMstBomChkSigen])';
var strMsg6 = '';
if( getMapVal( mapBlock , 'SASIZU_SYUBETU' ) == 'U'){
var strSigen = getMapVal( mapBlock , 'SIGEN_CODE' ).split(";");
for (var i in strSigen) {
var strSQL =
"SELECT * " +
"FROM ( " +
" SELECT " +
" SIGEN1.PROJECTID " +
" ,'U' AS SASIZU_SYUBETU " +
" ,SIGEN1.SIGEN_CODE AS CODE " +
" ,SIGEN1.SIGEN_NM AS NM " +
" ,SIGEN1.SIGEN_GROUP AS GRP " +
" ,SIGEN2.SIGEN_NM AS GRP_NM " +
" ,CASE WHEN SIGENG.SIGEN_GROUP IS NOT NULL THEN 'グループ設定あり' END AS MST_UMU " +
" FROM ASP_M_SIGEN SIGEN1 " +
" LEFT OUTER JOIN ASP_M_SIGEN SIGEN2 ON SIGEN1.PROJECTID = SIGEN2.PROJECTID AND SIGEN1.SIGEN_GROUP = SIGEN2.SIGEN_CODE " +
" LEFT OUTER JOIN ( " +
" SELECT PROJECTID,SIGEN_GROUP FROM ASP_M_SIGEN GROUP BY PROJECTID,SIGEN_GROUP " +
" ) SIGENG ON SIGEN1.PROJECTID = SIGENG.PROJECTID AND SIGEN1.SIGEN_CODE = SIGENG.SIGEN_GROUP " +
" UNION " +
" /** 資源グループに設定されていて、資源の登録がないデータを補完 **/ " +
" SELECT " +
" SIGEN1.PROJECTID " +
" ,'U' AS SASIZU_SYUBETU " +
" ,SIGEN1.SIGEN_GROUP AS CODE " +
" ,NULL AS NM " +
" ,NULL AS GRP " +
" ,NULL AS GRP_NM " +
" ,'グループ設定ありマスタなし' AS MST_UMU " +
" FROM ASP_M_SIGEN SIGEN1 " +
" WHERE SIGEN1.SIGEN_GROUP IS NOT NULL " +
" AND NOT EXISTS (SELECT 1 FROM ASP_M_SIGEN SIGENG WHERE SIGEN1.PROJECTID = SIGENG.PROJECTID AND SIGEN1.SIGEN_GROUP = SIGENG.SIGEN_CODE) " +
" GROUP BY SIGEN1.PROJECTID,SIGEN1.SIGEN_GROUP " +
") SIGEN " +
"WHERE PROJECTID = '"+ getMapVal( mapBlock , 'PROJECTID' ) +"' " +
"AND CODE = '"+ strSigen[i] +"' ";
TALON.getLogger().writeInfo(strFuncNm+strStepMsg+" SQL:"+strSQL);
var lstSelect = TALON.select(strSQL);
if(lstSelect.size() == 0){
if( getMapVal( mapBlock , 'OBJECTID' ) != null && getMapVal( mapBlock , 'OBJECTID' ) != ''){
strMsg6 = "、OBJECTID["+ getMapVal( mapBlock , 'OBJECTID' ) +"]";
}
TALON.addErrorMsg("資源["+ strSigen[i] +"]が存在しません。(PJ["+ getMapVal( mapBlock , 'PROJECTID' ) +"]、品目["+ getMapVal( mapBlock , 'ITEM_CODE' ) +"]、"+"工程番号["+ getMapVal( mapBlock , 'KOUTEI_NO' ) +"]"
+"指図種別["+ getMapVal( mapBlock , 'SASIZU_SYUBETU' ) +"]、指図コード["+ getMapVal( mapBlock , 'SASIZU_CODE' ) +"]、品目/資源コード["+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"]"+ strMsg6 +")");
TALON.setIsSuccess(false);
break;
}
}
}else{
var strSQL =
"SELECT * " +
"FROM ( " +
" SELECT " +
" ITEM1.PROJECTID " +
" ,ITEM1.ITEM_CODE AS CODE " +
" ,ITEM1.ITEM_NM AS NM " +
" ,ITEM1.ITEM_GROUP AS GRP " +
" ,ITEM2.ITEM_NM AS GRP_NM " +
" ,NULL AS MST_UMU " +
" FROM ASP_M_ITEM ITEM1 " +
" LEFT OUTER JOIN ASP_M_ITEM ITEM2 ON ITEM1.PROJECTID = ITEM2.PROJECTID AND ITEM1.ITEM_GROUP = ITEM2.ITEM_CODE " +
" /** 製造BOMの入力指図の品目に品目グループは設定不可のため除外 **/ " +
" WHERE NOT EXISTS (SELECT 1 FROM ASP_M_ITEM ITEMG WHERE ITEM1.PROJECTID = ITEMG.PROJECTID AND ITEM1.ITEM_CODE = ITEMG.ITEM_GROUP) " +
" UNION " +
" /** 製造BOMの工程NOから、品目の登録がない中間品データを補完 **/ " +
" SELECT " +
" MST.PROJECTID " +
" ,MST.CODE " +
" ,NULL AS NM " +
" ,NULL AS GRP " +
" ,NULL AS GRP_NM " +
" ,'マスタなし' AS MST_UMU " +
" FROM ( " +
" SELECT " +
" PROJECTID " +
" ,CONCAT(CONCAT(ITEM_CODE,'-'),KOUTEI_NO) AS CODE " +
" FROM ASP_M_BOM BOM " +
" WHERE NOT EXISTS ( " +
" SELECT 1 FROM (SELECT PROJECTID,ITEM_CODE,MAX(KOUTEI_NO) AS KOUTEI_NO FROM ASP_M_BOM GROUP BY PROJECTID,ITEM_CODE) MAXNO " +
" WHERE BOM.PROJECTID = MAXNO.PROJECTID AND BOM.ITEM_CODE = MAXNO.ITEM_CODE AND BOM.KOUTEI_NO = MAXNO.KOUTEI_NO " +
" ) " +
" GROUP BY PROJECTID,ITEM_CODE,KOUTEI_NO " +
" ) MST " +
" WHERE NOT EXISTS (SELECT 1 FROM ASP_M_ITEM ITM WHERE MST.PROJECTID = ITM.PROJECTID AND MST.CODE = ITM.ITEM_CODE) " +
") ITEM " +
"WHERE PROJECTID = '"+ getMapVal( mapBlock , 'PROJECTID' ) +"' " +
"AND CODE = '"+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"' ";
TALON.getLogger().writeInfo(strFuncNm+strStepMsg+" SQL:"+strSQL);
var lstSelect = TALON.select(strSQL);
if(lstSelect.size() == 0){
if( getMapVal( mapBlock , 'OBJECTID' ) != null && getMapVal( mapBlock , 'OBJECTID' ) != ''){
strMsg6 = "、OBJECTID["+ getMapVal( mapBlock , 'OBJECTID' ) +"]";
}
TALON.addErrorMsg("品目["+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"]が存在しません。(PJ["+ getMapVal( mapBlock , 'PROJECTID' ) +"]、品目["+ getMapVal( mapBlock , 'ITEM_CODE' ) +"]、"+"工程番号["+ getMapVal( mapBlock , 'KOUTEI_NO' ) +"]"
+"指図種別["+ getMapVal( mapBlock , 'SASIZU_SYUBETU' ) +"]、指図コード["+ getMapVal( mapBlock , 'SASIZU_CODE' ) +"]、品目/資源コード["+ getMapVal( mapBlock , 'SIGEN_CODE' ) +"]"+ strMsg6 +")");
TALON.setIsSuccess(false);
}
}
}
≣ サーバJS ライブラリASP_SETUP JavaScriptエンジン共通コード(ASP_SETUP) 129652字
/**
* セットアップ共通(環境構築)
*
* @version 2019/10/09
*/
//--------------------------------------------
// セットアップ関連共通
//--------------------------------------------
function table_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_TABLES WHERE TABLE_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM information_schema.tables WHERE table_name = '" + nm + "' AND table_schema = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'U' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(DISTINCT table_name) AS CNT FROM information_schema.columns WHERE LOWER(table_name) = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function function_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_PROCEDURES WHERE OBJECT_TYPE = 'FUNCTION' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = '" + _DSP1 + "' AND SPECIFIC_NAME = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'FN' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_proc WHERE proname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function view_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_OBJECTS WHERE OBJECT_TYPE = 'VIEW' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '" + nm + "' AND TABLE_SCHEMA = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'V' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_class WHERE relkind = 'v' and relname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function field_exists(nm,fl) {
if ( !TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = '" + nm + "' AND COLUMN_NAME = '" + fl + "' " );
} else {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = LOWER('" + nm + "') AND COLUMN_NAME = LOWER('" + fl + "') " );
}
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function executeSQL(sql) {
if ( TALON.getDbConfig().isOra() ) {
//Oracleの場合true
TALON.executeSQL(sql);
};
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isPostgres() ) {
//Postgresの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
}
function table_exists_drop(nm) {
if (table_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP TABLE " + nm ) ;
} else {
executeSQL( "DROP TABLE " + nm.toLowerCase() ) ;
}
}
}
function function_exists_drop(nm) {
if (function_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP FUNCTION " + nm ) ;
} else {
executeSQL( "DROP FUNCTION " + nm.toLowerCase() ) ;
}
}
}
function view_exists_drop(nm) {
if (view_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP VIEW " + nm ) ;
} else {
executeSQL( "DROP VIEW " + nm.toLowerCase() ) ;
}
}
}
//--------------------------------------------
// セットアップ後環境別データ修正
//--------------------------------------------
function exec_custom() {
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
if ( chkLowercase() ) {
//lowercaseとして判断
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_KBN = 'UPDATE_TABLE' AND FUNC_ID LIKE 'ASP_%' ");
}
}
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
var array = ["TLN_CHAR_TO_DATE", "TLN_CHAR_TO_NUMBER", "TLN_CHARINDEX", "TLN_CONCAT", "TLN_DATE_TIME_TO_CHAR", "TLN_DATE_TIME_TO_DATETIME", "TLN_DATE_TO_CHAR", "TLN_DATE_TO_WEEKDAY", "TLN_DATEADD", "TLN_DATEDIFF", "TLN_FIRSTDAY", "TLN_LEN", "TLN_LF", "TLN_MID", "TLN_ROUND", "TLN_ROUND_INT", "TLN_SYSDATE"]
var i;
var num = array.length;
for(i=0;i < num;i++){
//--------------
//TLN_M_GENERAL_FUNC_SQL
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_FUNC_SQL " +
" SET " +
" BODY_SQL = REPLACE(REPLACE(BODY_SQL ,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" ,TITLE_SQL = REPLACE(REPLACE(TITLE_SQL,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'ASP_%' "
);
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_ITEM_OPTN " +
" SET " +
" CHR_TEXT = REPLACE(REPLACE(CHR_TEXT,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_ID <> 'ASP_SYS0010' " +
" AND (FUNC_KBN = 'JAVA_SCRIPT_ENGINE' OR (FUNC_KBN = 'BUTTON_BAT' AND FLAG = 2)) "
);
//--------------
//TLN_M_HANYO_CODE_MAIN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_HANYO_CODE_MAIN " +
" SET " +
" NOTE = REPLACE(REPLACE(NOTE,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
" AND KEY_CODE <> 'ASP_SETUP' "
);
}
}
if ( TALON.getDbConfig().isPostgres() ) {
//PostgreSQLの場合true
//lower
//--------------
//TLN_M_GENERAL_ITEM
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_ID <> 'ASP_SYS0010' ");
//--------------
//TLN_M_GENERAL_FUNC_SQL
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%ITEM_CODE%' , LOWER('%ITEM_CODE%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%PROJECTID%' , LOWER('%PROJECTID%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%YM%' , LOWER('%YM%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%SIGEN_CODE%' , LOWER('%SIGEN_CODE%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%ITEM_SYUBETU_I%' , LOWER('%ITEM_SYUBETU_I%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%TENKAI_HOUKOU%' , LOWER('%TENKAI_HOUKOU%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%USER_ID%' , LOWER('%USER_ID%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%OPERATION_KBN%' , LOWER('%OPERATION_KBN%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%YMPLN_YYYYMM_SEARCH%' , LOWER('%YMPLN_YYYYMM_SEARCH%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%DEL_FLG_SEARCH%' , LOWER('%DEL_FLG_SEARCH%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%ALL_SEARCH%' , LOWER('%ALL_SEARCH%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%PLN_YM%' , LOWER('%PLN_YM%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%SEL_END_DATA_INCLUDE%' , LOWER('%SEL_END_DATA_INCLUDE%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%SIGEN_SEIYAKU_KBN%' , LOWER('%SIGEN_SEIYAKU_KBN%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%BACK_COLOR_FUNC%' , LOWER('%BACK_COLOR_FUNC%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%PROJECTID_1%' , LOWER('%PROJECTID_1%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%PROJECTID_2%' , LOWER('%PROJECTID_2%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%AVGKIKAN%' , LOWER('%AVGKIKAN%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = replace( BODY_SQL , '%STDEV%' , LOWER('%STDEV%') ) WHERE FUNC_ID LIKE 'ASP_%' ");
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_SEQ > -1 AND ( FUNC_KBN IN ('BACK_COLOR' , 'CSV_LOAD_BUTTON_COL' , 'CSV_OUT_BUTTON_COL' , 'DISP_POS' , 'DRILL_DOWN' , 'FIX_FORMULA' , 'FOCUS_OUT_JAVASCRIPT' , 'FORE_COLOR' , 'INIT_VALUE_TEXT' , 'INPUT_CONDITION' , 'JAVASCRIPT' , 'JAVASCRIPT_ENGINE' , 'XX_JAVA_SCRIPT_ENGINE' , 'JOIN' , 'LOOK_UP' , 'LOOK_UP_FUNC_ID' , 'MASTER_CHECK' , 'MATCH_PATTERN' , 'REGIST_VALUE' , 'REQUIRED_SEARCH' , 'SAIBAN_SIKIBETU_CODE' , 'SEARCH_FUNC_ID' , 'SEARCH_METHOD' , 'SUB_SEARCH' , 'IS_DB_NOT_REGIST' , 'SUGGEST_FUNC_ID' , 'SUGGEST' , 'BARCODE_FORMAT' , 'THUMBNAIL_SIZE' , '' ) OR FUNC_KBN LIKE 'BUTTON_NEXT_%' ) ");
// -- BACK_COLOR
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%ITEM_CODE%' , LOWER('%ITEM_CODE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%DUP_FLG%' , LOWER('%DUP_FLG%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%OPE_FLG%' , LOWER('%OPE_FLG%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%HENKO_NG_FLG%' , LOWER('%HENKO_NG_FLG%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%SAGYO_STATUS%' , LOWER('%SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%KOUTEI_CODE%' , LOWER('%KOUTEI_CODE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%PROJECTID_KBN%', LOWER('%PROJECTID_KBN%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%DATA_KBN%' , LOWER('%DATA_KBN%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BACK_COLOR' ");
// -- BUTTON_NEXT
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace( CHR4 , '%1_ORDER_SYUBETU%', LOWER('%1_ORDER_SYUBETU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace( CHR4 , '%1_DATA_KBN%' , LOWER('%1_DATA_KBN%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace( CHR4 , '%1_ORDER_STATUS%' , LOWER('%1_ORDER_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace( CHR4 , '%1_SAGYO_STATUS%' , LOWER('%1_SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
// -- BUTTON_NEXT_x
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN LIKE 'BUTTON_NEXT_%' ");
// -- CHART
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) , CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'CHART' AND COL_NAME IN ('CHART_SERIES_BASE' , 'CHART_AXIS_X_BASE') ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) , CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN='CHART' AND COL_NAME LIKE 'CHART_SERIES_ONCLICK_%' AND COL_NAME <> 'CHART_SERIES_ONCLICK_WINSIZE' ");
// -- FORE_COLOR
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%SAGYO_STATUS%', LOWER('%SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'FORE_COLOR' ");
// -- INIT_VALUE_TEXT
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = replace( CHR1 , '%PROJECTID%', LOWER('%PROJECTID%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'INIT_VALUE_TEXT' ");
// -- INPUT_CONDITION
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_DEL_FLG%' , LOWER('%1_DEL_FLG%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'INPUT_CONDITION' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_ORDER_SYUBETU%' , LOWER('%1_ORDER_SYUBETU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'INPUT_CONDITION' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SASIZU_SYUBETU%', LOWER('%1_SASIZU_SYUBETU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'INPUT_CONDITION' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SAGYO_STATUS%' , LOWER('%1_SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'INPUT_CONDITION' ");
// -- LOOK_UP
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1),CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'LOOK_UP' ");
// -- MATCH_PATTERN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_ORDER_SU%' , LOWER('%1_ORDER_SU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_ORDER_SYUBETU%' , LOWER('%1_ORDER_SYUBETU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SAGYO_STATUS%' , LOWER('%1_SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_END_DATE%' , LOWER('%1_END_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SEIZO_SU%' , LOWER('%1_SEIZO_SU%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SIGEN_CODE%' , LOWER('%1_SIGEN_CODE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_START_DATE%' , LOWER('%1_START_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SEIZO_START_DATE%' , LOWER('%1_SEIZO_START_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_SEIZO_END_DATE%' , LOWER('%1_SEIZO_END_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_MAE_DANDORI_END_DATE%' , LOWER('%1_MAE_DANDORI_END_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = replace( KIND , '%1_MAE_DANDORI_START_DATE%' , LOWER('%1_MAE_DANDORI_START_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
// -- REGIST_VALUE
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'REGIST_VALUE' AND CHR1 NOT IN ('\"B\"','\"T\"') ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%2_SAGYO_STATUS%' , LOWER('%2_SAGYO_STATUS%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'REGIST_VALUE' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = replace( CHR2 , '%1_SEIZO_END_DATE%' , LOWER('%1_SEIZO_END_DATE%') ) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'REGIST_VALUE' ");
// -- SUB_SEARCH
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1),CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'SUB_SEARCH' ");
// -- SUGGEST
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1),CHR2 = LOWER(CHR2),CHR3 = LOWER(CHR3) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN = 'SUGGEST' ");
//TLN_M_GENERAL_APP
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_ID LIKE 'ASP_%' AND FUNC_KBN IN ('UPDATE_TABLE' , 'SCHEDULE_EVENT_TEXT_COL','SCHEDULE_EVENT_TOOLTIP_COL','SCHEDULE_FROM_DATE_COL','SCHEDULE_TITLE_COL','SCHEDULE_TO_DATE_COL','SCHEDULE_UNIQUE_COL','SCHEDULE_CONNECT_TO_COL' ) ");
//TLN_M_GENERAL_USES
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_USES SET KEY_CODE = LOWER(KEY_CODE) WHERE FUNC_ID LIKE 'ASP_%' AND USER_CODE = 'TLN_GEN_ALL' AND OPTN IN ( 'ITEM', 'ASC', 'DESC', 'DRILL_LEVEL') ");
}
}
function exec_object( _func_chk ){
//画面でファンクションの再構築が設定された場合(初回インストールは固定1で呼び出される)
if ( _func_chk == '1' ) {
//ファンクションの再構築 →ファンクション・Viewはパッチ毎に最新を作成
exec_create_Function();
//Viewの再構築 →ファンクション・Viewはパッチ毎に最新を作成
exec_create_View();
}
}
function exec_create_Function() {
//≪FUNCTION DROP≫
//--------------------
//
// function_exists_drop('XXXXXXXXXX');
// *
// * if ( TALON.getDbConfig().isOra() ) {
// * //
// * executeSQL(
// * "CREATE FUNCTION XXXXXX ( " + "\n" +
// * ""
// * );
// *
// * };
// * if ( TALON.getDbConfig().isMy() ) {
// * //
// * //SQLファイルで作成
// *
// * };
// * if ( TALON.getDbConfig().isMssql() ) {
// * //
// * executeSQL(
// * "CREATE FUNCTION XXXXXX ( " + "\n" +
// * ""
// * );
// *
// * };
// * if ( TALON.getDbConfig().isPostgres() ) {
// * //
// * //SQLファイルで作成
// *
// * };
}
function exec_create_View() {
//≪VIEW DROP≫
//--------------------
//
view_exists_drop('ASP_V_SAGYO_JSK_TO_ASPROVA');
//
view_exists_drop('ASP_V_SAGYO_OPE_TO_ASPROVA');
//
view_exists_drop('ASP_V_ORDER_TO_ASPROVA');
//
view_exists_drop('ASP_V_SAGYO_INFO_ATO');
//
view_exists_drop('ASP_V_SAGYO_INFO_MAE');
//
view_exists_drop('ASP_V_SAGYO_INFO');
//
view_exists_drop('ASP_V_SAGYO_JSK');
//
view_exists_drop('ASP_V_SAGYO_OPE');
//--------------------
executeSQL(
"CREATE VIEW ASP_V_SAGYO_JSK_TO_ASPROVA AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_JSK.PROJECTID " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_SYS.ORDER_CODE " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_NO " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL THEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE ELSE ASP_SAGYO_JSK.SEIZO_START_DATE END AS START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_END_DATE AS END_DATE " + "\n" +
" " + "\n" +
" ,ASP_SAGYO_JSK.SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_SU " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_STATUS " + "\n" +
" ,ASP_SAGYO_JSK.FURYO_SU " + "\n" +
" ,ASP_SAGYO_JSK.SAIKI_FLG " + "\n" +
" " + "\n" +
"FROM ASP_SAGYO_JSK " + "\n" +
"INNER JOIN ASP_SAGYO_SYS " + "\n" +
" ON ASP_SAGYO_JSK.PROJECTID = ASP_SAGYO_SYS.PROJECTID " + "\n" +
" AND ASP_SAGYO_JSK.SAGYO_CODE = ASP_SAGYO_SYS.SAGYO_CODE " + "\n" +
"INNER JOIN ASP_ORDER_SYS " + "\n" +
" ON ASP_SAGYO_SYS.ORDER_CODE = ASP_ORDER_SYS.ORDER_CODE " + "\n" +
" AND ASP_ORDER_SYS.DEL_FLG IS NULL " + "\n" +
"-- 実績入力 オーダ未完了分がインポート対象 " + "\n" +
"WHERE ASP_ORDER_SYS.ORDER_STATUS <> 'B' " + "\n" +
""
);
//--------------------
executeSQL(
"CREATE VIEW ASP_V_SAGYO_OPE_TO_ASPROVA AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_OPE.PROJECTID " + "\n" +
" ,ASP_SAGYO_OPE.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_SYS.ORDER_CODE " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_NO " + "\n" +
" ,ASP_SAGYO_OPE.START_DATE " + "\n" +
" ,ASP_SAGYO_OPE.END_DATE " + "\n" +
" ,ASP_SAGYO_SYS.SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_OPE.SEND_KBN " + "\n" +
" ,'D' AS STATUS " + "\n" +
" ,'1' AS IMP_TIME_ALLOCATE_FLG " + "\n" +
" ,'1' AS TLN_IMP_FLG " + "\n" +
"FROM ASP_SAGYO_OPE " + "\n" +
"INNER JOIN ASP_SAGYO_SYS " + "\n" +
" ON ASP_SAGYO_OPE.PROJECTID = ASP_SAGYO_SYS.PROJECTID " + "\n" +
" AND ASP_SAGYO_OPE.SAGYO_CODE = ASP_SAGYO_SYS.SAGYO_CODE " + "\n" +
"INNER JOIN ASP_ORDER_SYS " + "\n" +
" ON ASP_SAGYO_SYS.ORDER_CODE = ASP_ORDER_SYS.ORDER_CODE " + "\n" +
" AND ASP_ORDER_SYS.DEL_FLG IS NULL " + "\n" +
"-- 計画調整 未送信分 オーダ未完了分がインポート対象 " + "\n" +
"WHERE ASP_SAGYO_OPE.SEND_KBN = '0' -- 0:未送信/1:送信済み計画中/2:送信済み計画終了/9:取消 " + "\n" +
" AND ASP_ORDER_SYS.ORDER_STATUS <> 'B' " + "\n" +
""
);
//--------------------
if ( TALON.getDbConfig().isMssql() ) {
executeSQL(
"CREATE VIEW ASP_V_ORDER_TO_ASPROVA AS " + "\n" +
"SELECT " + "\n" +
" ASP_ORDER_SYS.PROJECTID AS PROJECTID " + "\n" +
" ,ASP_ORDER_SYS.ORDER_CODE AS ORDER_CODE " + "\n" +
" ,ASP_ORDER_SYS.ORDER_SYUBETU AS ORDER_SYUBETU " + "\n" +
" ,ASP_ORDER_SYS.ITEM_CODE AS ITEM_CODE " + "\n" +
" ,dbo.TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.NOKI_DATE) AS NOKI_DATE " + "\n" +
" ,ASP_ORDER_SYS.ORDER_SU AS ORDER_SU " + "\n" +
" ,ASP_ORDER_SYS.YUSENDO AS YUSENDO " + "\n" +
" ,ASP_ORDER_SYS.NOTE AS NOTE " + "\n" +
" ,ASP_ORDER_SYS.SIYO1 AS SIYO1 " + "\n" +
" ,ASP_ORDER_SYS.SIYO2 AS SIYO2 " + "\n" +
" ,ASP_ORDER_SYS.SIYO3 AS SIYO3 " + "\n" +
" ,ASP_ORDER_SYS.SIYO4 AS SIYO4 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM1 AS SIYO_NUM1 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM2 AS SIYO_NUM2 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM3 AS SIYO_NUM3 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM4 AS SIYO_NUM4 " + "\n" +
" ,ASP_ORDER_SYS.ORDER_KBN AS ORDER_KBN " + "\n" +
" ,ASP_ORDER_SYS.ORDER_STATUS AS ORDER_STATUS " + "\n" +
" ,dbo.TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.JSK_START_DATE) AS JSK_START_DATE " + "\n" +
" ,dbo.TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.JSK_END_DATE) AS JSK_END_DATE " + "\n" +
" ,ASP_ORDER_SYS.JSK_ORDER_SU AS JSK_ORDER_SU " + "\n" +
"FROM ASP_ORDER_SYS " + "\n" +
"-- オーダーは削除されたもの、完了ステータスのもの以外はインポート対象とする(洗い替え) " + "\n" +
"WHERE ASP_ORDER_SYS.DEL_FLG IS NULL " + "\n" +
" AND ASP_ORDER_SYS.ORDER_STATUS <> 'B' " + "\n" +
""
);
} else {
executeSQL(
"CREATE VIEW ASP_V_ORDER_TO_ASPROVA AS " + "\n" +
"SELECT " + "\n" +
" ASP_ORDER_SYS.PROJECTID AS PROJECTID " + "\n" +
" ,ASP_ORDER_SYS.ORDER_CODE AS ORDER_CODE " + "\n" +
" ,ASP_ORDER_SYS.ORDER_SYUBETU AS ORDER_SYUBETU " + "\n" +
" ,ASP_ORDER_SYS.ITEM_CODE AS ITEM_CODE " + "\n" +
" ,TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.NOKI_DATE) AS NOKI_DATE " + "\n" +
" ,ASP_ORDER_SYS.ORDER_SU AS ORDER_SU " + "\n" +
" ,ASP_ORDER_SYS.YUSENDO AS YUSENDO " + "\n" +
" ,ASP_ORDER_SYS.NOTE AS NOTE " + "\n" +
" ,ASP_ORDER_SYS.SIYO1 AS SIYO1 " + "\n" +
" ,ASP_ORDER_SYS.SIYO2 AS SIYO2 " + "\n" +
" ,ASP_ORDER_SYS.SIYO3 AS SIYO3 " + "\n" +
" ,ASP_ORDER_SYS.SIYO4 AS SIYO4 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM1 AS SIYO_NUM1 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM2 AS SIYO_NUM2 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM3 AS SIYO_NUM3 " + "\n" +
" ,ASP_ORDER_SYS.SIYO_NUM4 AS SIYO_NUM4 " + "\n" +
" ,ASP_ORDER_SYS.ORDER_KBN AS ORDER_KBN " + "\n" +
" ,ASP_ORDER_SYS.ORDER_STATUS AS ORDER_STATUS " + "\n" +
" ,TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.JSK_START_DATE) AS JSK_START_DATE " + "\n" +
" ,TLN_DATE_TO_CHAR('YMDHMS', ASP_ORDER_SYS.JSK_END_DATE) AS JSK_END_DATE " + "\n" +
" ,ASP_ORDER_SYS.JSK_ORDER_SU AS JSK_ORDER_SU " + "\n" +
"FROM ASP_ORDER_SYS " + "\n" +
"-- オーダーは削除されたもの、完了ステータスのもの以外はインポート対象とする(洗い替え) " + "\n" +
"WHERE ASP_ORDER_SYS.DEL_FLG IS NULL " + "\n" +
" AND ASP_ORDER_SYS.ORDER_STATUS <> 'B' " + "\n" +
""
);
}
//--------------------
if ( TALON.getDbConfig().isMssql() ) {
executeSQL(
"CREATE VIEW ASP_V_SAGYO_JSK AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_JSK.PROJECTID " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_JSK.ORDER_CODE " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL THEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE ELSE ASP_SAGYO_JSK.SEIZO_START_DATE END AS START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_END_DATE AS END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.KOUTEI_CODE " + "\n" +
" ,ASP_SAGYO_JSK.KOUTEI_NO " + "\n" +
" -- ASPROVAで実績入力時、資源コードが省略されるパターンあり(その場合は計画のもとを使用) " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.SIGEN_CODE IS NULL THEN ASP_SAGYO_SYS.SIGEN_CODE ELSE ASP_SAGYO_JSK.SIGEN_CODE END SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_SU " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_STATUS " + "\n" +
" ,ASP_SAGYO_JSK.MAE_DANDORI_START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.MAE_DANDORI_END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_TEISI_TIME " + "\n" +
" ,ASP_SAGYO_JSK.SAIKI_FLG " + "\n" +
" ,ASP_SAGYO_JSK.FURYO_SU " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_SAGYO_JSK.FURYO_SU IS NULL THEN ASP_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE ASP_SAGYO_JSK.SEIZO_SU - ASP_SAGYO_JSK.FURYO_SU " + "\n" +
" END AS NORMAL_SU " + "\n" +
" -- BOM段取実績 : 開始、終了が登録されている場合出力、計算対象 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN dbo.TLN_DATEDIFF('S', ASP_SAGYO_JSK.MAE_DANDORI_END_DATE, ASP_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 " + "\n" +
" END AS MAE_DANDORI_TIME " + "\n" +
" -- 製造時間には停止時間(分)を考慮(実績時間_秒 / 60 - 実績時間_分) " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.SEIZO_START_DATE IS NOT NULL AND ASP_SAGYO_JSK.SEIZO_END_DATE IS NOT NULL THEN " + "\n" +
" ( dbo.TLN_DATEDIFF('S', ASP_SAGYO_JSK.SEIZO_END_DATE, ASP_SAGYO_JSK.SEIZO_START_DATE) / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ELSE 0 END AS SEIZO_TIME " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_DATE " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_BY " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_DATE " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_BY " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_JSK.MODIFY_COUNT " + "\n" +
"FROM ASP_SAGYO_JSK " + "\n" +
"LEFT OUTER JOIN ASP_SAGYO_SYS " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_SAGYO_JSK.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_SAGYO_JSK.SAGYO_CODE " + "\n" +
""
);
} else {
executeSQL(
"CREATE VIEW ASP_V_SAGYO_JSK AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_JSK.PROJECTID " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_JSK.ORDER_CODE " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL THEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE ELSE ASP_SAGYO_JSK.SEIZO_START_DATE END AS START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_END_DATE AS END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.KOUTEI_CODE " + "\n" +
" ,ASP_SAGYO_JSK.KOUTEI_NO " + "\n" +
" -- ASPROVAで実績入力時、資源コードが省略されるパターンあり(その場合は計画のもとを使用) " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.SIGEN_CODE IS NULL THEN ASP_SAGYO_SYS.SIGEN_CODE ELSE ASP_SAGYO_JSK.SIGEN_CODE END SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_SU " + "\n" +
" ,ASP_SAGYO_JSK.SAGYO_STATUS " + "\n" +
" ,ASP_SAGYO_JSK.MAE_DANDORI_START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.MAE_DANDORI_END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_START_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_END_DATE " + "\n" +
" ,ASP_SAGYO_JSK.SEIZO_TEISI_TIME " + "\n" +
" ,ASP_SAGYO_JSK.SAIKI_FLG " + "\n" +
" ,ASP_SAGYO_JSK.FURYO_SU " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_SAGYO_JSK.FURYO_SU IS NULL THEN ASP_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE ASP_SAGYO_JSK.SEIZO_SU - ASP_SAGYO_JSK.FURYO_SU " + "\n" +
" END AS NORMAL_SU " + "\n" +
" -- BOM段取実績 : 開始、終了が登録されている場合出力、計算対象 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN TLN_DATEDIFF('S', ASP_SAGYO_JSK.MAE_DANDORI_END_DATE, ASP_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 " + "\n" +
" END AS MAE_DANDORI_TIME " + "\n" +
" -- 製造時間には停止時間(分)を考慮(実績時間_秒 / 60 - 実績時間_分) " + "\n" +
" ,CASE WHEN ASP_SAGYO_JSK.SEIZO_START_DATE IS NOT NULL AND ASP_SAGYO_JSK.SEIZO_END_DATE IS NOT NULL THEN " + "\n" +
" ( TLN_DATEDIFF('S', ASP_SAGYO_JSK.SEIZO_END_DATE, ASP_SAGYO_JSK.SEIZO_START_DATE) / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ELSE 0 END AS SEIZO_TIME " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_DATE " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_BY " + "\n" +
" ,ASP_SAGYO_JSK.CREATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_DATE " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_BY " + "\n" +
" ,ASP_SAGYO_JSK.UPDATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_JSK.MODIFY_COUNT " + "\n" +
"FROM ASP_SAGYO_JSK " + "\n" +
"LEFT OUTER JOIN ASP_SAGYO_SYS " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_SAGYO_JSK.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_SAGYO_JSK.SAGYO_CODE " + "\n" +
""
);
}
//--------------------
executeSQL(
"CREATE VIEW ASP_V_SAGYO_OPE AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_OPE.PROJECTID " + "\n" +
" ,ASP_SAGYO_OPE.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_OPE.START_DATE " + "\n" +
" ,ASP_SAGYO_OPE.END_DATE " + "\n" +
" ,ASP_SAGYO_OPE.SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_OPE.SEND_KBN " + "\n" +
" ,ASP_SAGYO_OPE.CREATED_DATE " + "\n" +
" ,ASP_SAGYO_OPE.CREATED_BY " + "\n" +
" ,ASP_SAGYO_OPE.CREATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_OPE.UPDATED_DATE " + "\n" +
" ,ASP_SAGYO_OPE.UPDATED_BY " + "\n" +
" ,ASP_SAGYO_OPE.UPDATED_PRG_NM " + "\n" +
" ,ASP_SAGYO_OPE.MODIFY_COUNT " + "\n" +
"FROM ASP_SAGYO_OPE " + "\n" +
"-- 実績データは1:未送信/2:送信済み計画中が対象(計画完了後はSYSが正となる) " + "\n" +
"WHERE ASP_SAGYO_OPE.SEND_KBN IN ( '0' , '1' ) " + "\n" +
""
);
//--------------------
if ( TALON.getDbConfig().isMssql() ) {
executeSQL(
"CREATE VIEW ASP_V_SAGYO_INFO AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_SYS.PROJECTID " + "\n" +
" ,ASP_SAGYO_SYS.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_SYS.ORDER_CODE " + "\n" +
" ,ASP_ORDER_SYS.ITEM_CODE " + "\n" +
" " + "\n" +
" -- 実績入力が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SAGYO_STATUS ELSE ASP_SAGYO_SYS.SAGYO_STATUS END SAGYO_STATUS " + "\n" +
" " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_CODE " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_NO " + "\n" +
" ,ASP_SAGYO_SYS.LT " + "\n" +
" " + "\n" +
" -- ガント操作が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.SIGEN_CODE ELSE ASP_SAGYO_SYS.SIGEN_CODE END AS SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_SYS.SEIZO_SU " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE ELSE ASP_SAGYO_SYS.START_DATE END AS START_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE ELSE ASP_SAGYO_SYS.END_DATE END AS END_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN '1' ELSE '0' END OPE_UMU_KBN " + "\n" +
" " + "\n" +
" -- 実績入力が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SIGEN_CODE ELSE ASP_SAGYO_SYS.JSK_SIGEN_CODE END AS JSK_SIGEN_CODE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END AS JSK_SEIZO_SU " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.START_DATE ELSE ASP_SAGYO_SYS.JSK_START_DATE END AS JSK_START_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.END_DATE ELSE ASP_SAGYO_SYS.JSK_END_DATE END AS JSK_END_DATE " + "\n" +
" " + "\n" +
" ,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE AS JSK_MAE_DANDORI_START_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE AS JSK_MAE_DANDORI_END_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_START_DATE AS JSK_SEIZO_START_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_END_DATE AS JSK_SEIZO_END_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME AS SEIZO_TEISI_TIME " + "\n" +
" ,ASP_V_SAGYO_JSK.SAIKI_FLG AS SAIKI_FLG " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END AS JSK_FURYO_SU " + "\n" +
" -- 不良数がnullの場合場合、製造数を表示する(算出で正常数がNULLになってしまうので) " + "\n" +
" ,CASE WHEN ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END ) IS NULL THEN " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END ) " + "\n" +
" ELSE " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END ) " + "\n" +
" - " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END ) " + "\n" +
" END AS JSK_NORMAL_SU " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN '1' ELSE '0' END JSK_UMU_KBN " + "\n" +
" " + "\n" +
" -- ガント表示用(ステータス、入力値を考慮し、TALON上の状態を取得) " + "\n" +
" -- ステータス:実績入力がある場合は実績入力でのステータス。以外の場合はSYSのステータスを表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SAGYO_STATUS ELSE ASP_SAGYO_SYS.SAGYO_STATUS END AS GANTT_SAGYO_STATUS " + "\n" +
" " + "\n" +
" -- 資源コード:実績入力がある場合は実績入力での資源コード。ガント変更がある場合はガント変更での資源コード。以外の場合はSYSの資源コード " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS IN ('B','T') THEN ASP_V_SAGYO_JSK.SIGEN_CODE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.SIGEN_CODE " + "\n" +
" ELSE ASP_SAGYO_SYS.SIGEN_CODE " + "\n" +
" END " + "\n" +
" END AS GANTT_SIGEN_CODE " + "\n" +
" " + "\n" +
" -- 実績入力の数量、開始日、終了日は「完了ステータス」で無いと反映させない(着手中は反映しない) " + "\n" +
" -- 製造数:実績入力がありステータスが完了の場合は実績入力の製造数。以外の場合はSYSの製造数 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN JSK_SEIZO_SU ELSE ASP_SAGYO_SYS.SEIZO_SU END " + "\n" +
" END AS GANTT_SEIZO_SU " + "\n" +
" " + "\n" +
" -- 開始日:実績入力がありステータスが完了の場合は実績入力の開始日、ガント変更がある場合はガント変更での開始日、 " + "\n" +
" -- 以外の場合、SYSのステータスが完了の場合は実績開始日、以外の場合は開始日を表示 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" -- ASP_SAGYO_SYSのステータスが完了の状態でOPEは操作できない前提 " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END AS GANTT_START_DATE " + "\n" +
" " + "\n" +
" -- 終了日:実績入力がありステータスが完了の場合は実績入力の終了日、ガント変更がある場合はガント変更での終了日、 " + "\n" +
" -- 以外の場合、SYSのステータスが完了の場合は実績終了日、以外の場合は終了日を表示 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" -- ASP_SAGYO_SYSのステータスが完了の状態でOPEは操作できない前提 " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END AS GANTT_END_DATE " + "\n" +
" " + "\n" +
" -- ガントチャートツールチップ(オーダガント、資源ガント) " + "\n" +
" , dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_1.DSP1 , ASP_SAGYO_SYS.ORDER_CODE ) " + "\n" +
" ,CONCAT( TOOLTIP_2.DSP1 , dbo.TLN_DATE_TO_CHAR( 'YMD' , ASP_ORDER_SYS.NOKI_DATE ) ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_3.DSP1 , ASP_SAGYO_SYS.SAGYO_CODE ) " + "\n" +
" ,dbo.TLN_CONCAT( '( ' , ' )' , ASP_SAGYO_SYS.KOUTEI_CODE ) " + "\n" +
" ,'' " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_4.DSP1 , ASP_ORDER_SYS.ITEM_CODE ) " + "\n" +
" ,CONCAT( TOOLTIP_5.DSP1 , " + "\n" +
" -- GANTT_SEIZO_SU " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN JSK_SEIZO_SU ELSE ASP_SAGYO_SYS.SEIZO_SU END " + "\n" +
" END " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( TOOLTIP_6.DSP1 , dbo.TLN_DATE_TO_CHAR( 'YMDHMS' , " + "\n" +
" -- GANTT_START_DATE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) , '' ) " + "\n" +
" ,dbo.TLN_CONCAT( TOOLTIP_7.DSP1 , dbo.TLN_DATE_TO_CHAR( 'YMDHMS' , " + "\n" +
" -- GANTT_END_DATE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) , '' ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_CONCAT( " + "\n" +
" dbo.TLN_CONCAT( TOOLTIP_8.DSP1 , CONCAT( dbo.TLN_ROUND('1' , 2 , " + "\n" +
" -- JSK_MAE_DANDORI_TIME " + "\n" +
" -- 段取り時間は実績より計算 " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN " + "\n" +
" dbo.TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 END " + "\n" +
" ),'') , '' ) " + "\n" +
" ,dbo.TLN_CONCAT( TOOLTIP_9.DSP1 , CONCAT( dbo.TLN_ROUND('1' , 2 , " + "\n" +
" -- JSK_SEIZO_TIME " + "\n" +
" -- 製造時間は完了の実績がある場合は実績(JSK)より、無い場合は計画調整(OPE)、もしくは作業情報(SYS)より計算(上記ガントの表示内容と同じ) " + "\n" +
" ( " + "\n" +
" dbo.TLN_DATEDIFF( " + "\n" +
" 'S', " + "\n" +
" -- 終了日時 " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END, " + "\n" +
" -- 終了日時 " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) " + "\n" +
" / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ),'') , '' ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) " + "\n" +
" ,dbo.TLN_LF() " + "\n" +
" ) as TOOLTIP " + "\n" +
" " + "\n" +
" -- BOM段取実績 : 開始、終了が登録されている場合出力、計算対象 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN " + "\n" +
" dbo.TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 END AS JSK_MAE_DANDORI_TIME " + "\n" +
" -- 製造時間には停止時間(分)を考慮(実績時間_秒 / 60 - 実績時間_分) " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SEIZO_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.SEIZO_END_DATE IS NOT NULL THEN " + "\n" +
" ( dbo.TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.SEIZO_END_DATE,ASP_V_SAGYO_JSK.SEIZO_START_DATE) / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ELSE 0 END AS JSK_SEIZO_TIME " + "\n" +
" " + "\n" +
"FROM ASP_SAGYO_SYS " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_ORDER_SYS " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_ORDER_SYS.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.ORDER_CODE = ASP_ORDER_SYS.ORDER_CODE " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_V_SAGYO_JSK " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_V_SAGYO_JSK.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_V_SAGYO_JSK.SAGYO_CODE " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_V_SAGYO_OPE " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_V_SAGYO_OPE.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_V_SAGYO_OPE.SAGYO_CODE " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_1 " + "\n" +
" ON TOOLTIP_1.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_1.KEY_CODE = '1' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_2 " + "\n" +
" ON TOOLTIP_2.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_2.KEY_CODE = '2' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_3 " + "\n" +
" ON TOOLTIP_3.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_3.KEY_CODE = '3' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_4 " + "\n" +
" ON TOOLTIP_4.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_4.KEY_CODE = '4' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_5 " + "\n" +
" ON TOOLTIP_5.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_5.KEY_CODE = '5' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_6 " + "\n" +
" ON TOOLTIP_6.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_6.KEY_CODE = '6' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_7 " + "\n" +
" ON TOOLTIP_7.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_7.KEY_CODE = '7' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_8 " + "\n" +
" ON TOOLTIP_8.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_8.KEY_CODE = '8' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_9 " + "\n" +
" ON TOOLTIP_9.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_9.KEY_CODE = '9' " + "\n" +
" " + "\n" +
""
);
} else {
executeSQL(
"CREATE VIEW ASP_V_SAGYO_INFO AS " + "\n" +
"SELECT " + "\n" +
" ASP_SAGYO_SYS.PROJECTID " + "\n" +
" ,ASP_SAGYO_SYS.SAGYO_CODE " + "\n" +
" ,ASP_SAGYO_SYS.ORDER_CODE " + "\n" +
" ,ASP_ORDER_SYS.ITEM_CODE " + "\n" +
" " + "\n" +
" -- 実績入力が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SAGYO_STATUS ELSE ASP_SAGYO_SYS.SAGYO_STATUS END SAGYO_STATUS " + "\n" +
" " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_CODE " + "\n" +
" ,ASP_SAGYO_SYS.KOUTEI_NO " + "\n" +
" ,ASP_SAGYO_SYS.LT " + "\n" +
" " + "\n" +
" -- ガント操作が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.SIGEN_CODE ELSE ASP_SAGYO_SYS.SIGEN_CODE END AS SIGEN_CODE " + "\n" +
" ,ASP_SAGYO_SYS.SEIZO_SU " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE ELSE ASP_SAGYO_SYS.START_DATE END AS START_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE ELSE ASP_SAGYO_SYS.END_DATE END AS END_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN '1' ELSE '0' END OPE_UMU_KBN " + "\n" +
" " + "\n" +
" -- 実績入力が実施されていればその内容を表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SIGEN_CODE ELSE ASP_SAGYO_SYS.JSK_SIGEN_CODE END AS JSK_SIGEN_CODE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END AS JSK_SEIZO_SU " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.START_DATE ELSE ASP_SAGYO_SYS.JSK_START_DATE END AS JSK_START_DATE " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.END_DATE ELSE ASP_SAGYO_SYS.JSK_END_DATE END AS JSK_END_DATE " + "\n" +
" " + "\n" +
" ,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE AS JSK_MAE_DANDORI_START_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE AS JSK_MAE_DANDORI_END_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_START_DATE AS JSK_SEIZO_START_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_END_DATE AS JSK_SEIZO_END_DATE " + "\n" +
" ,ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME AS SEIZO_TEISI_TIME " + "\n" +
" ,ASP_V_SAGYO_JSK.SAIKI_FLG AS SAIKI_FLG " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END AS JSK_FURYO_SU " + "\n" +
" -- 不良数がnullの場合場合、製造数を表示する(算出で正常数がNULLになってしまうので) " + "\n" +
" ,CASE WHEN ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END ) IS NULL THEN " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END ) " + "\n" +
" ELSE " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SEIZO_SU ELSE ASP_SAGYO_SYS.JSK_SEIZO_SU END ) " + "\n" +
" - " + "\n" +
" ( CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.FURYO_SU ELSE ASP_SAGYO_SYS.JSK_FURYO_SU END ) " + "\n" +
" END AS JSK_NORMAL_SU " + "\n" +
" " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN '1' ELSE '0' END JSK_UMU_KBN " + "\n" +
" " + "\n" +
" -- ガント表示用(ステータス、入力値を考慮し、TALON上の状態を取得) " + "\n" +
" -- ステータス:実績入力がある場合は実績入力でのステータス。以外の場合はSYSのステータスを表示 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_JSK.SAGYO_STATUS ELSE ASP_SAGYO_SYS.SAGYO_STATUS END AS GANTT_SAGYO_STATUS " + "\n" +
" " + "\n" +
" -- 資源コード:実績入力がある場合は実績入力での資源コード。ガント変更がある場合はガント変更での資源コード。以外の場合はSYSの資源コード " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS IN ('B','T') THEN ASP_V_SAGYO_JSK.SIGEN_CODE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.SIGEN_CODE " + "\n" +
" ELSE ASP_SAGYO_SYS.SIGEN_CODE " + "\n" +
" END " + "\n" +
" END AS GANTT_SIGEN_CODE " + "\n" +
" " + "\n" +
" -- 実績入力の数量、開始日、終了日は「完了ステータス」で無いと反映させない(着手中は反映しない) " + "\n" +
" -- 製造数:実績入力がありステータスが完了の場合は実績入力の製造数。以外の場合はSYSの製造数 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN JSK_SEIZO_SU ELSE ASP_SAGYO_SYS.SEIZO_SU END " + "\n" +
" END AS GANTT_SEIZO_SU " + "\n" +
" " + "\n" +
" -- 開始日:実績入力がありステータスが完了の場合は実績入力の開始日、ガント変更がある場合はガント変更での開始日、 " + "\n" +
" -- 以外の場合、SYSのステータスが完了の場合は実績開始日、以外の場合は開始日を表示 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" -- ASP_SAGYO_SYSのステータスが完了の状態でOPEは操作できない前提 " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END AS GANTT_START_DATE " + "\n" +
" " + "\n" +
" -- 終了日:実績入力がありステータスが完了の場合は実績入力の終了日、ガント変更がある場合はガント変更での終了日、 " + "\n" +
" -- 以外の場合、SYSのステータスが完了の場合は実績終了日、以外の場合は終了日を表示 " + "\n" +
" ,CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" -- ASP_SAGYO_SYSのステータスが完了の状態でOPEは操作できない前提 " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END AS GANTT_END_DATE " + "\n" +
" " + "\n" +
" -- ガントチャートツールチップ(オーダガント、資源ガント) " + "\n" +
" , TLN_CONCAT( " + "\n" +
" TLN_CONCAT( " + "\n" +
" TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_1.DSP1 , ASP_SAGYO_SYS.ORDER_CODE ) " + "\n" +
" ,CONCAT( TOOLTIP_2.DSP1 , TLN_DATE_TO_CHAR( 'YMD' , ASP_ORDER_SYS.NOKI_DATE ) ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_CONCAT( " + "\n" +
" TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_3.DSP1 , ASP_SAGYO_SYS.SAGYO_CODE ) " + "\n" +
" ,TLN_CONCAT( '( ' , ' )' , ASP_SAGYO_SYS.KOUTEI_CODE ) " + "\n" +
" ,'' " + "\n" +
" ) " + "\n" +
" ,TLN_CONCAT( " + "\n" +
" CONCAT( TOOLTIP_4.DSP1 , ASP_ORDER_SYS.ITEM_CODE ) " + "\n" +
" ,CONCAT( TOOLTIP_5.DSP1 , " + "\n" +
" -- GANTT_SEIZO_SU " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.SEIZO_SU " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN JSK_SEIZO_SU ELSE ASP_SAGYO_SYS.SEIZO_SU END " + "\n" +
" END " + "\n" +
" ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_CONCAT( " + "\n" +
" TLN_CONCAT( " + "\n" +
" TLN_CONCAT( TOOLTIP_6.DSP1 , TLN_DATE_TO_CHAR( 'YMDHMS' , " + "\n" +
" -- GANTT_START_DATE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) , '' ) " + "\n" +
" ,TLN_CONCAT( TOOLTIP_7.DSP1 , TLN_DATE_TO_CHAR( 'YMDHMS' , " + "\n" +
" -- GANTT_END_DATE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) , '' ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_CONCAT( " + "\n" +
" TLN_CONCAT( TOOLTIP_8.DSP1 , CONCAT( TLN_ROUND('1' , 2 , " + "\n" +
" -- JSK_MAE_DANDORI_TIME " + "\n" +
" -- 段取り時間は実績より計算 " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN " + "\n" +
" TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 END " + "\n" +
" ),'') , '' ) " + "\n" +
" ,TLN_CONCAT( TOOLTIP_9.DSP1 , CONCAT( TLN_ROUND('1' , 2 , " + "\n" +
" -- JSK_SEIZO_TIME " + "\n" +
" -- 製造時間は完了の実績がある場合は実績(JSK)より、無い場合は計画調整(OPE)、もしくは作業情報(SYS)より計算(上記ガントの表示内容と同じ) " + "\n" +
" ( " + "\n" +
" TLN_DATEDIFF( " + "\n" +
" 'S', " + "\n" +
" -- 終了日時 " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.END_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.END_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_END_DATE ELSE ASP_SAGYO_SYS.END_DATE END " + "\n" +
" END " + "\n" +
" END, " + "\n" +
" -- 終了日時 " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_JSK.SAGYO_CODE IS NOT NULL and ASP_V_SAGYO_JSK.SAGYO_STATUS = 'B' THEN ASP_V_SAGYO_JSK.START_DATE " + "\n" +
" ELSE " + "\n" +
" CASE " + "\n" +
" WHEN ASP_V_SAGYO_OPE.SAGYO_CODE IS NOT NULL THEN ASP_V_SAGYO_OPE.START_DATE " + "\n" +
" ELSE CASE WHEN ASP_SAGYO_SYS.SAGYO_STATUS = 'B' THEN ASP_SAGYO_SYS.JSK_START_DATE ELSE ASP_SAGYO_SYS.START_DATE END " + "\n" +
" END " + "\n" +
" END " + "\n" +
" ) " + "\n" +
" / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ),'') , '' ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) " + "\n" +
" ,TLN_LF() " + "\n" +
" ) as TOOLTIP " + "\n" +
" " + "\n" +
" -- BOM段取実績 : 開始、終了が登録されている場合出力、計算対象 " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE IS NOT NULL THEN " + "\n" +
" TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.MAE_DANDORI_END_DATE,ASP_V_SAGYO_JSK.MAE_DANDORI_START_DATE) / 60 " + "\n" +
" ELSE 0 END AS JSK_MAE_DANDORI_TIME " + "\n" +
" -- 製造時間には停止時間(分)を考慮(実績時間_秒 / 60 - 実績時間_分) " + "\n" +
" ,CASE WHEN ASP_V_SAGYO_JSK.SEIZO_START_DATE IS NOT NULL AND ASP_V_SAGYO_JSK.SEIZO_END_DATE IS NOT NULL THEN " + "\n" +
" ( TLN_DATEDIFF('S',ASP_V_SAGYO_JSK.SEIZO_END_DATE,ASP_V_SAGYO_JSK.SEIZO_START_DATE) / 60 ) " + "\n" +
" - " + "\n" +
" CASE WHEN ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME IS NULL THEN 0 ELSE ASP_V_SAGYO_JSK.SEIZO_TEISI_TIME END " + "\n" +
" ELSE 0 END AS JSK_SEIZO_TIME " + "\n" +
" " + "\n" +
"FROM ASP_SAGYO_SYS " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_ORDER_SYS " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_ORDER_SYS.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.ORDER_CODE = ASP_ORDER_SYS.ORDER_CODE " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_V_SAGYO_JSK " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_V_SAGYO_JSK.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_V_SAGYO_JSK.SAGYO_CODE " + "\n" +
" " + "\n" +
"LEFT OUTER JOIN ASP_V_SAGYO_OPE " + "\n" +
" ON ASP_SAGYO_SYS.PROJECTID = ASP_V_SAGYO_OPE.PROJECTID " + "\n" +
" AND ASP_SAGYO_SYS.SAGYO_CODE = ASP_V_SAGYO_OPE.SAGYO_CODE " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_1 " + "\n" +
" ON TOOLTIP_1.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_1.KEY_CODE = '1' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_2 " + "\n" +
" ON TOOLTIP_2.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_2.KEY_CODE = '2' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_3 " + "\n" +
" ON TOOLTIP_3.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_3.KEY_CODE = '3' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_4 " + "\n" +
" ON TOOLTIP_4.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_4.KEY_CODE = '4' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_5 " + "\n" +
" ON TOOLTIP_5.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_5.KEY_CODE = '5' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_6 " + "\n" +
" ON TOOLTIP_6.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_6.KEY_CODE = '6' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_7 " + "\n" +
" ON TOOLTIP_7.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_7.KEY_CODE = '7' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_8 " + "\n" +
" ON TOOLTIP_8.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_8.KEY_CODE = '8' " + "\n" +
" " + "\n" +
" LEFT OUTER JOIN TLN_M_HANYO_CODE_MAIN TOOLTIP_9 " + "\n" +
" ON TOOLTIP_9.SIKIBETU_CODE = 'ASP_TOOLTIP_TITLE' " + "\n" +
" AND TOOLTIP_9.KEY_CODE = '9' " + "\n" +
" " + "\n" +
""
);
}
//--------------------
executeSQL(
"CREATE VIEW ASP_V_SAGYO_INFO_MAE AS " + "\n" +
"SELECT " + "\n" +
" ASP_HIMO.PROJECTID " + "\n" +
" , ASP_HIMO.ORDER_CODE_RIGHT AS ORDER_CODE_MY " + "\n" +
" , ASP_HIMO.SAGYO_CODE_RIGHT AS SAGYO_CODE_MY " + "\n" +
" , MAX( ASP_V_SAGYO_INFO.GANTT_END_DATE ) AS MAX_END_DATE " + "\n" +
"FROM ASP_HIMO " + "\n" +
"INNER JOIN ASP_V_SAGYO_INFO " + "\n" +
" ON ASP_HIMO.PROJECTID = ASP_V_SAGYO_INFO.PROJECTID " + "\n" +
" AND ASP_HIMO.SAGYO_CODE_LEFT = ASP_V_SAGYO_INFO.SAGYO_CODE " + "\n" +
"WHERE ASP_HIMO.ORDER_CODE_RIGHT = ASP_HIMO.ORDER_CODE_LEFT " + "\n" +
"GROUP BY " + "\n" +
" ASP_HIMO.PROJECTID " + "\n" +
" , ORDER_CODE_RIGHT " + "\n" +
" , SAGYO_CODE_RIGHT " + "\n" +
""
);
//--------------------
executeSQL(
"CREATE VIEW ASP_V_SAGYO_INFO_ATO AS " + "\n" +
"SELECT " + "\n" +
" ASP_HIMO.PROJECTID " + "\n" +
" , ASP_HIMO.ORDER_CODE_LEFT AS ORDER_CODE_MY " + "\n" +
" , ASP_HIMO.SAGYO_CODE_LEFT AS SAGYO_CODE_MY " + "\n" +
" , MIN( ASP_V_SAGYO_INFO.GANTT_START_DATE ) AS MIN_START_DATE " + "\n" +
"FROM ASP_HIMO " + "\n" +
"INNER JOIN ASP_V_SAGYO_INFO " + "\n" +
" ON ASP_HIMO.PROJECTID = ASP_V_SAGYO_INFO.PROJECTID " + "\n" +
" AND ASP_HIMO.SAGYO_CODE_RIGHT = ASP_V_SAGYO_INFO.SAGYO_CODE " + "\n" +
"WHERE ASP_HIMO.ORDER_CODE_RIGHT = ASP_HIMO.ORDER_CODE_LEFT " + "\n" +
"GROUP BY " + "\n" +
" ASP_HIMO.PROJECTID " + "\n" +
" , ORDER_CODE_LEFT " + "\n" +
" , SAGYO_CODE_LEFT " + "\n" +
""
);
}
//--------------------------------------------
// 言語設定変更
//--------------------------------------------
function change_language(to_lang) {
//現時点の言語を取得
var now_lang = getLanguageType();
if ( now_lang != '0' && now_lang != '1' && now_lang != '2' ) {
//パラメータ不正
TALON.addErrorMsg( "Error : Invalid parameter (now_language) " );
TALON.setIsSuccess(false);
return false;
}
if ( to_lang != '0' && to_lang != '1' && to_lang != '2' ) {
//パラメータ不正
TALON.addErrorMsg( "Error : Invalid parameter (to_language)" );
TALON.setIsSuccess(false);
return false;
}
//機能IDの更新(TLN_M_GENERAL_FUNC)
var map = {
'ASP_BGT1110' : ['資源別予実照会(日別)[ASP_BGT1110]','Budget and Results by Resource [ASP_BGT1110]',''],
'ASP_BGT1120' : ['資源別予実照会(日別)[ASP_BGT1120]','Budget and Results by Resource [ASP_BGT1120]',''],
'ASP_BGT1210' : ['資源・品目別予実照会(日別)[ASP_BGT1210]','Budget and Results by Item [ASP_BGT1210]',''],
'ASP_BGT1220' : ['資源・品目別予実照会(日別)[ASP_BGT1220]','Budget and Results by Item [ASP_BGT1220]',''],
'ASP_BGT1400' : ['予実オーダガントチャート[ASP_BGT1400]','Budget and Results by Order Gantt [ASP_BGT1400]',''],
'ASP_COP2200' : ['月間計画作成[ASP_COP2200]','Monthly Planning [ASP_COP2200]',''],
'ASP_MST0020' : ['資源マスタ検索子画面[ASP_MST0020]','Search Resource Master [ASP_MST0020]',''],
'ASP_MST0021' : ['資源マスタ検索子画面[ASP_MST0021]','Search Resource Master [ASP_MST0021]',''],
'ASP_MST0022' : ['資源マスタ(グループ)検索子画面[ASP_MST0022]','Search Resource Master (Groups) [ASP_MST0020]',''],
'ASP_MST0030' : ['工程マスタ検索子画面[ASP_MST0030]','Search Process Master [ASP_MST0030]',''],
'ASP_MST0040' : ['品目マスタ検索子画面[ASP_MST0040]','Search Item Master [ASP_MST0040]',''],
'ASP_MST0041' : ['品目マスタ検索子画面[ASP_MST0041]','Search Item Master [ASP_MST0041]',''],
'ASP_MST0042' : ['品目マスタ検索子画面[ASP_MST0042]','Search Item Master [ASP_MST0042]',''],
'ASP_MST0043' : ['品目マスタ(グループ)検索子画面[ASP_MST0043]','Search Item Master (Groups) [ASP_MST0043]',''],
'ASP_MST0050' : ['品目/資源マスタ検索子画面[ASP_MST0050]','Search Item / Resource Master [ASP_MST0050]',''],
'ASP_MST0060' : ['オーダ情報検索子画面[ASP_MST0060]','Search Order Information [ASP_MST0060]',''],
'ASP_MST0100' : ['製造BOMマスタメンテナンス[ASP_MST0100]','Maintenance Integrated Master [ASP_MST0100]',''],
'ASP_MST0400' : ['製造BOM段取り製造時間メンテナンス[ASP_MST0400]','Maintenance SetupTime Master [ASP_MST0400]',''],
'ASP_MST0600' : ['品目マスタメンテナンス[ASP_MST0600]','Maintenance Item Master [ASP_MST0600]',''],
'ASP_MST0700' : ['工程マスタメンテナンス[ASP_MST0700]','Maintenance Process Master [ASP_MST0700]',''],
'ASP_MST0800' : ['資源マスタメンテナンス[ASP_MST0800]','Maintenance Reource Master [ASP_MST0800]',''],
'ASP_MST0900' : ['構成照会[ASP_MST0900]','Inquiry Configuration [ASP_MST0900]',''],
'ASP_ORD0100' : ['オーダ一覧照会/メンテナンス[ASP_ORD0100]','Maintenance Order List [ASP_ORD0100]',''],
'ASP_ORD0300' : ['オーダ・作業/メンテナンス[ASP_ORD0300]','Maintenance Order / Operation List [ASP_ORD0300]',''],
'ASP_ORD0400' : ['作業一覧・指示書発行[ASP_ORD0400]','Operation List / Instruction [ASP_ORD0400]',''],
'ASP_ORD0410' : ['作業情報詳細[ASP_ORD0410]','Operation Information Details [ASP_ORD0410]',''],
'ASP_ORD0500' : ['作業実績入力[ASP_ORD0500]','Entry Operation Result [ASP_ORD0500]',''],
'ASP_ORD0600' : ['作業照会[ASP_ORD0600](スマートフォン)','Operation List (Smartphone) [ASP_ORD0600]',''],
'ASP_ORD0610' : ['作業実績入力[ASP_ORD0610](スマートフォン)','Entry Operation Result (Smartphone) [ASP_ORD0610]',''],
'ASP_ORD0700' : ['作業実績一括入力[ASP_ORD0700]','Entry Operation Result (Bulkupdate) [ASP_ORD0700]',''],
'ASP_PLN0110' : ['オーダガントチャート(動的表示)[ASP_PLN0110]','Order Ganttchart (Display) [ASP_PLN0110]',''],
'ASP_PLN0120' : ['オーダガントチャート(編集有)[ASP_PLN0120]','Order Ganttchart (Entry) [ASP_PLN0120]',''],
'ASP_PLN0210' : ['資源ガントチャート(動的表示)[ASP_PLN0210]','Resource Ganttchart (Display) [ASP_PLN0210]',''],
'ASP_PLN0220' : ['資源ガントチャート(編集有)[ASP_PLN0220]','Resource Ganttchart (Entry) [ASP_PLN0220]',''],
'ASP_PLN0310' : ['作業スケジュールカレンダ(動的表示)[ASP_PLN0310]','Operation Schedule (Display) [ASP_PLN0310]',''],
'ASP_PLN0320' : ['作業スケジュールカレンダー(編集有)[ASP_PLN0320]','Operation Schedule (Entry) [ASP_PLN0320]',''],
'ASP_PLN0400' : ['計画調整データ取消[ASP_PLN0400]','Cancel Operation Change Data [ASP_PLN0400]',''],
'ASP_PLN0500' : ['複数計画比較オーダガントチャート[ASP_PLN0500]','Multiple Plan Order Ganttchart [ASP_PLN0500]',''],
'ASP_PLN0600' : ['複数計画比較資源ガントチャート[ASP_PLN0600]','Multiple Plan Resource Ganttchart [ASP_PLN0600]',''],
'ASP_PLN0700' : ['ガントチャート・カレンダーカラー変更[ASP_PLN0700]','Ganttchart / Schedule Color Ghange [ASP_PLN0700]',''],
'ASP_PLN1110' : ['負荷グラフ照会[ASP_PLN1110]','Inquiry Load Graph [ASP_PLN1110]',''],
'ASP_SYS0010' : ['セットアップ・初期化[ASP_SYS0010]','System Setup / Initialization [ASP_SYS0010]',''],
'ASP_SYS0011' : ['メニュー構成データ登録[ASP_SYS0011]','System Setup Menu-Data Registration [ASP_SYS0011]',''],
'ASP_SYS0020' : ['サンプルデータ登録[ASP_SYS0020]','System Setup Sample-Date Entry [ASP_SYS0020]','']
}
for (key in map) {
var sql = "" +
"UPDATE TLN_M_GENERAL_FUNC SET FUNC_NM = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + key + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//ブロック名の更新(TLN_M_GENERAL_FUNC_SQL)
var map = {
'ASP_MST0100#0' : ['BOM','BOM',''],
'ASP_ORD0100#0' : ['オーダ','Order',''],
'ASP_ORD0300#0' : ['オーダ','Order',''],
'ASP_MST0060#0' : ['オーダ','Order',''],
'ASP_BGT1400#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0110#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0120#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0210#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0220#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0500#0' : ['ガントチャート','Ganttchart',''],
'ASP_PLN0600#0' : ['ガントチャート','Ganttchart',''],
'ASP_BGT1120#2' : ['グラフ','Graph',''],
'ASP_BGT1220#1' : ['グラフ','Graph',''],
'ASP_PLN0310#0' : ['スケジュール','Schedule',''],
'ASP_PLN0320#0' : ['スケジュール','Schedule',''],
'ASP_BGT1210#0' : ['予実','Budget and Results',''],
'ASP_COP2200#0' : ['作成','Create',''],
'ASP_ORD0300#1' : ['作業','Operation',''],
'ASP_ORD0400#0' : ['作業','Operation',''],
'ASP_ORD0600#0' : ['作業','Operation',''],
'ASP_ORD0610#0' : ['作業','Operation',''],
'ASP_MST0040#0' : ['品目','Item',''],
'ASP_MST0041#0' : ['品目','Item',''],
'ASP_MST0042#0' : ['品目','Item',''],
'ASP_MST0043#0' : ['品目','Item',''],
'ASP_MST0600#0' : ['品目','Item',''],
'ASP_MST0050#0' : ['品目/資源','Item / Resource',''],
'ASP_BGT1110#1' : ['対象','Target',''],
'ASP_MST0030#0' : ['工程','Process',''],
'ASP_MST0700#0' : ['工程','Process',''],
'ASP_MST0900#0' : ['構成照会','Inquiry Configuration',''],
'ASP_MST0400#0' : ['製造BOM','Integrated',''],
'ASP_PLN0400#0' : ['計画調整一覧','Operation Change Data',''],
'ASP_ORD0410#0' : ['詳細','Detail',''],
'ASP_ORD0500#0' : ['詳細','Detail',''],
'ASP_ORD0700#0' : ['詳細','Detail',''],
'ASP_PLN1110#1' : ['負荷グラフ','Load Graph',''],
'ASP_MST0020#0' : ['資源','Resource',''],
'ASP_MST0021#0' : ['資源','Resource',''],
'ASP_MST0022#0' : ['資源','Resource',''],
'ASP_MST0800#0' : ['資源','Resource',''],
'ASP_PLN1110#0' : ['資源','Resource',''],
'ASP_SYS0020#4' : ['オーダ情報ASP_ORDER_SYS','Order ASP_ORDER_SYS',''],
'ASP_SYS0020#5' : ['作業情報ASP_SAGYO_SYS','Operation ASP_SAGYO_SYS',''],
'ASP_SYS0020#1' : ['品目マスタASP_M_ITEM','Item ASP_M_ITEM',''],
'ASP_SYS0020#2' : ['工程マスタASP_M_KOUTEI','Process ASP_M_KOUTEI',''],
'ASP_SYS0020#0' : ['製造BOMマスタASP_M_BOM','Integrated ASP_M_BOM',''],
'ASP_SYS0020#6' : ['紐付けASP_HIMO','Peg ASP_HIMO',''],
'ASP_SYS0020#3' : ['資源マスタASP_M_SIGEN','Resource ASP_M_SIGEN',''],
'ASP_SYS0011#1' : ['グループ構成','Group Constitution',''],
'ASP_SYS0011#0' : ['機能グループ','Function Group',''],
'ASP_SYS0011#2' : ['機能グループ構成','Function Group Constitution','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_FUNC_SQL SET TITLE = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " ";
//TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//画面項目の更新(TLN_M_GENERAL_ITEM)
//画面項目はCOL_NAMEで変換を実施、ただし同じCOL_NAMEでも異なる名称もあるため、COL_NAMEと変換前文字列を条件に変換を実施
var map = {
'APP_URL#1' : ['機能毎APP_URL','Application url',''],
'ATO_DANDORI_END_DATE#2' : ['後段取り終了日時','Teardown end time',''],
'ATO_DANDORI_START_DATE#3' : ['後段取り開始日時','Teardown start time',''],
'ATO_DANDORI_TIME#4' : ['後段取り','Teardown',''],
'ATO_DANDORI_TIME#5' : ['後段取り時間','Teardown time',''],
'AUTH_KBN#6' : ['権限区分 0:参照 1:更新','Authorization classification',''],
'AVGKIKAN#7' : ['過去平均','Past average',''],
'AVG_MAE_DANDORI_TIME#8' : ['前段取り(過去平均)','Setup (Past average)',''],
'AVG_SAGYO_TIME#9' : ['製造(過去平均)','Production (Past average)',''],
'BACK_COLOR_FUNC#10' : ['対象機能','Target ',''],
'BOM_VERSION#11' : ['バージョン','Version',''],
'BUDOMARI#12' : ['歩留まり率(1は100%)','Yield rate (1=100%)',''],
'CHR2#13' : ['条件式','Conditional expression',''],
'CODE#14' : ['品目/資源コード','Item / Resource code',''],
'CREATED_BY#15' : ['作成者','Created auther',''],
'CREATED_DATE#16' : ['作成日','Created date',''],
'CREATED_PRG_NM#17' : ['作成プログラム名','Created program',''],
'DEL_FLG#18' : ['削除','Delete',''],
'DEL_FLG#19' : ['削除フラグ','Delete flag',''],
'DEL_FLG_SEARCH#20' : ['削除を検索','Search delete',''],
'EARLIEST_START_DATE#21' : ['最早開始日時','EST',''],
'END_DATE#22' : ['終了日時','End date',''],
'END_DATE_YMD#23' : ['終了日 ','End date',''],
'EVENT_NAIYO#24' : ['イベント内容','Event contents',''],
'FUKA_1#25' : ['負荷(PJ1)','Load (PJ1)',''],
'FUKA_2#26' : ['負荷(PJ2)','Load (PJ2)',''],
'FUNC_ATH_ID#27' : ['グループID','Group id',''],
'FUNC_ATH_ID#28' : ['機能グループID','Function group id',''],
'FUNC_CHK#29' : ['ファンクションチェック','Function check',''],
'FUNC_GRP_ID#30' : ['グループID','Function group id',''],
'FUNC_ID#31' : ['機能ID','Function id',''],
'FUNC_NM#32' : ['機能名','Function name',''],
'FURYO_SU#33' : ['不良数','Scrap quantity',''],
'GRP#34' : ['品目/資源グループ','Item / Resource groups',''],
'GRP#35' : ['レベル1品目コード','Item code (Lv.1)',''],
'GRP_FLG#36' : ['レベル1品目','Item (Lv.1)',''],
'GRP_NM#37' : ['品目/資源グループ名','Item / Resource groups name',''],
'GRP_NM#38' : ['レベル1品目名','Item name (Lv.1)',''],
'HELP_URL#39' : ['機能毎HELP_URL','Function help url',''],
'HITUYO_SIGENRYO#40' : ['必要資源量','Required resource quantity',''],
'HIZUKE#41' : ['工程納期','Process due date',''],
'ITEM_AUTO_HOJU_FLG#42' : ['自動補充フラグ','Auto-replenish flag',''],
'ITEM_CODE#43' : ['品目コード','Item code',''],
'ITEM_GROUP#44' : ['品目グループ','Item groups',''],
'ITEM_GROUP_NM#45' : ['品目グループ名','Item groups name',''],
'ITEM_NM#46' : ['品目名','Item nm',''],
'ITEM_NM_DSP#47' : ['品目名','Item nm (display)',''],
'ITEM_SYUBETU#48' : ['品目種別','Item type',''],
'ITEM_SYUBETU_I#49' : ['中間品','Intermediate item',''],
'ITEM_TANKA#50' : ['品目単価','Item unit price',''],
'JSK_END_DATE#51' : ['実績終了日時','Reported end time',''],
'JSK_END_DATE_YMD#52' : ['実績終了日','Reported end date',''],
'JSK_ORDER_SU#53' : ['実績数量','Reported qty',''],
'JSK_SEIZO_SU#54' : ['実績数量','Reported qty',''],
'JSK_SEIZO_TIME#55' : ['実績製造時間:分','Reported time',''],
'JSK_SIGEN_CODE#56' : ['実績資源コード','Reported resource',''],
'JSK_SIGEN_GROUP#57' : ['実績資源グループ','Reported resource groups',''],
'JSK_SIGEN_GROUP_NM#58' : ['実績資源グループ名','Reported resource groups name',''],
'JSK_SIGEN_NM#59' : ['実績資源名','Reported resource name',''],
'JSK_START_DATE#60' : ['実績開始日時','Reported start time',''],
'JSK_START_DATE_YMD#61' : ['実績開始日','Reported start date',''],
'JSK_SU#62' : ['実績数','Reported qty',''],
'JSK_SU_KEI#63' : ['実績数計','Reported qty (total)',''],
'KASANARI_HOUHOU#64' : ['重なり方法','Time constraint method',''],
'KASANARI_MAX#65' : ['重なりMAX','Time constraint MAX',''],
'KASANARI_MIN#66' : ['重なりMIN','Time constraint MIN',''],
'KIND#67' : ['バーカラー','Color',''],
'KIND_DSP#68' : ['color','Color Image',''],
'KIND_SEL#69' : ['バーカラー(選択)','Color (select)',''],
'KOBAI_LOT_MAX#70' : ['購買ロットサイズMAX','Purchase lot size MAX',''],
'KOBAI_LOT_MIN#71' : ['購買ロットサイズMIN','Purchase lot size MIN',''],
'KOBAI_LOT_UNIT#72' : ['購買ロットサイズUNIT','Purchase lot size UNIT',''],
'KOUTEI_CODE#73' : ['工程コード','Process code',''],
'KOUTEI_NM#74' : ['工程名','Process name',''],
'KOUTEI_NO#75' : ['工順','Process number',''],
'KOUTEI_SELECTOR#76' : ['工程セレクタ','Process selector',''],
'KOUTEI_SELECTOR_JKN#77' : ['工程セレクタ有効条件','Process selector valid condition',''],
'KOUTEI_SORT#78' : ['ソード','Sort',''],
'LAST_MAE_DANDORI_TIME#79' : ['前段取り(直近)','Setup (recent)',''],
'LAST_SAGYO_TIME#80' : ['製造(直近)','Production (recent)',''],
'LOAD_INFO_KBN#81' : ['負荷グラフ対象','Load graph target',''],
'LT#82' : ['リードタイム','Lead time',''],
'LVL#83' : ['レベル','Level',''],
'MAE_DANDORI_END_DATE#84' : ['前段取り終了日時','Setup end time',''],
'MAE_DANDORI_START_DATE#85' : ['前段取り開始日時','Setup start time',''],
'MAE_DANDORI_TIME#86' : ['前段取り','Setup',''],
'MAE_DANDORI_TIME#87' : ['前段取り時間','Setup time',''],
'MODIFY_COUNT#88' : ['更新数','Updated number',''],
'MST_UMU#89' : ['登録状況','Registration status',''],
'NM#90' : ['品目/資源名','Item / Resource',''],
'NOKI_DATE#91' : ['納 期','Due date',''],
'NOKI_OKURE#92' : ['納期遅れを検索','Due date delay',''],
'NORMAL_SU#93' : ['正常数','Normal quantity',''],
'NOTE#94' : ['コメント','Comment',''],
'OBJECTID#95' : ['オブジェクトID','Object id',''],
'OPT_SORT#96' : ['№','No.',''],
'ORDER_CODE#97' : ['オーダコード','Order code',''],
'ORDER_CODE#98' : ['オーダコード(表示)','Order code (display)',''],
'ORDER_CODE_DISP#99' : ['オーダコード(表示)','Order code (display)',''],
'ORDER_CODE_KEY#100' : ['オーダコード','Order code',''],
'ORDER_CODE_KEY#101' : ['オーダコード(遷移)','Order code (transition)',''],
'ORDER_CODE_LEFT#102' : ['オーダコードLEFT','Order code (left)',''],
'ORDER_CODE_RIGHT#103' : ['オーダコードRIGHT','Order code (right)',''],
'ORDER_CODE_SORT#104' : ['オーダコード(順番)','Order code (sort)',''],
'ORDER_KBN#105' : ['オーダ区分','Order class',''],
'ORDER_STATUS#106' : ['ステータス','Order status',''],
'ORDER_SU#107' : ['オーダ数量','Order quantity',''],
'ORDER_SYUBETU#108' : ['オーダ種別','Order type',''],
'PLN_END_DATE#109' : ['終了日時','Plan end time',''],
'PLN_SEIZO_SU#110' : ['製造数量','Plan production quantity',''],
'PLN_SIGEN_CODE#111' : ['資源コード','Plan resource code',''],
'PLN_SIGEN_GROUP#112' : ['資源グループ','Plan resource groups',''],
'PLN_SIGEN_NM#113' : ['資源名','Plan resource name',''],
'PLN_START_DATE#114' : ['開始日時','Plan start time',''],
'PLN_SU#115' : ['計画数','Plan quantity',''],
'PLN_SU_KEI#116' : ['計画数計','Plan quantity (total)',''],
'PLN_YM#117' : ['計画月度','Plan monthly',''],
'PREV_KOUTEI_NO#118' : ['先行工順','Previous process number',''],
'PRINT_SORT#119' : ['出力ソート順','Sort',''],
'PROJECTID#120' : ['PJ','PJ',''],
'PROJECTID_1#121' : ['PJ1','PJ1',''],
'PROJECTID_2#122' : ['PJ2','PJ2',''],
'PROJECTNM_1#123' : ['PJNM1','PJNM1',''],
'PROJECTNM_2#124' : ['PJNM2','PJNM2',''],
'SAGYO_CODE#125' : ['作業コード','Code',''],
'SAGYO_CODE_LEFT#126' : ['作業コードLEFT','Code (left)',''],
'SAGYO_CODE_RIGHT#127' : ['作業コードRIGHT','Code (right)',''],
'SAGYO_LOT_MAX#128' : ['作業LOT MAX','Operation split size MAX',''],
'SAGYO_LOT_MIN#129' : ['作業LOT MIN','Operation split size MIN',''],
'SAGYO_LOT_UNIT#130' : ['作業LOT UNIT','Operation split size UNIT',''],
'SAGYO_STATUS#131' : ['ステータス','Status',''],
'SAGYO_STATUS#132' : ['更新後ステータス','Status (after)',''],
'SAGYO_STATUS_NOW#133' : ['ステータス','Status',''],
'SAGYO_STATUS_PRE#134' : ['ステータス(変更前)','Status (before)',''],
'SAIKI_FLG#135' : ['再帰実績フラグ','Result recursive flag',''],
'SASIZU_CODE#136' : ['指図コード','Instruction code',''],
'SASIZU_SYUBETU#137' : ['指図種別','Instruction type',''],
'SCRAP_SU#138' : ['スクラップ数','Scrap quantity',''],
'SEARCH_KBN_ITEM#139' : ['検索品目区分','Item class (search)',''],
'SEARCH_KBN_SIGEN#140' : ['検索資源区分','Resource class (search)',''],
'SEIZO#141' : ['数量','Quantity',''],
'SEIZO#142' : ['製造','Production',''],
'SEIZO_END_DATE#143' : ['実績終了日時','Reported end time',''],
'SEIZO_END_DATE#144' : ['製造終了日時','Produciton end time',''],
'SEIZO_KORITU#145' : ['製造効率','Production factor',''],
'SEIZO_LOT_MAX#146' : ['製造ロットサイズMAX','Production lot size MAX',''],
'SEIZO_LOT_MIN#147' : ['製造ロットサイズMIN','Production lot size MIN',''],
'SEIZO_LOT_UNIT#148' : ['製造ロットサイズUNIT','Production lot size UNIT',''],
'SEIZO_START_DATE#149' : ['実績開始日時','Reported start time',''],
'SEIZO_START_DATE#150' : ['製造開始日時','Production start time',''],
'SEIZO_SU#151' : ['実績数量','Reported quantity',''],
'SEIZO_SU#152' : ['製造数','Production quantity',''],
'SEIZO_TEISI_TIME#153' : ['実績停止時間:分','Reported stop time (min)',''],
'SEIZO_TIME#154' : ['製造数量','Produciton time',''],
'SEL_END_DATA_INCLUDE#155' : ['完了含む','Including complete',''],
'SIGEN_CODE#156' : ['品目/資源コード','Item / Resource ',''],
'SIGEN_CODE#157' : ['実績資源コード','Reported Resource',''],
'SIGEN_CODE#158' : ['資源コード','Resource code',''],
'SIGEN_CODE#159' : ['資源コード(表示)','Resource code (display)',''],
'SIGEN_CODE#160' : ['集計資源','Resource code (total)',''],
'SIGEN_CODE_KEY#161' : ['資源コード','Resource code',''],
'SIGEN_CODE_SORT#162' : ['資源コード(順番)','Resource code (sort)',''],
'SIGEN_COMMENT#163' : ['コメント','Comment',''],
'SIGEN_GROUP#164' : ['資源グループ','Resource groups',''],
'SIGEN_GROUP_NM#165' : ['資源グループ名','Resource groups name',''],
'SIGEN_KBN#166' : ['資源区分','Resource class',''],
'SIGEN_NM#167' : ['実績資源名','Reported resource name',''],
'SIGEN_NM#168' : ['資源名','Resource name',''],
'SIGEN_NM_DISP#169' : ['資源','Resource name',''],
'SIGEN_NM_DSP#170' : ['資源名','Resource name',''],
'SIGEN_SEIYAKU#171' : ['資源制約','Resource quantity constraints',''],
'SIGEN_SEIYAKU_KBN#172' : ['資源無制限を含める','Include resource quantity not constraints',''],
'SIGEN_SYUBETU#173' : ['資源種別','Resource type',''],
'SIGEN_YUSENDO#174' : ['資源優先度','Resource priority',''],
'SIYO1#175' : ['仕様1','Specification 1',''],
'SIYO2#176' : ['仕様2','Specification 2',''],
'SIYO3#177' : ['仕様3','Specification 3',''],
'SIYO4#178' : ['仕様4','Specification 4',''],
'SIYO_NUM1#179' : ['数値仕様1','Specification (numeric) 1',''],
'SIYO_NUM2#180' : ['数値仕様2','Specification (numeric) 2',''],
'SIYO_NUM3#181' : ['数値仕様3','Specification (numeric) 3',''],
'SIYO_NUM4#182' : ['数値仕様4','Specification (numeric) 4',''],
'START_DATE#183' : ['開始日時','Start date',''],
'START_DATE_TO_GANTTO#184' : ['開始日時(ガント遷移用)','Start date (gantto)',''],
'START_DATE_YMD#185' : ['開始日 ','Start date',''],
'STDEV#186' : ['実績除外','Resource exclusion',''],
'SUM_MAE_DANDORI_TIME#187' : ['前段取り(合計)','Setup (total)',''],
'SUM_SAGYO_TIME#188' : ['製造(合計)','Produciton time (total)',''],
'SURYO#189' : ['個数','Quantity',''],
'TASK_SELECTOR#190' : ['タスクセレクタ','Task selector',''],
'TASK_SELECTOR_JKN#191' : ['タスクセレクタ有効条件','Task selector valid conditon',''],
'TENKAI_HOUKOU#192' : ['展開方向','Deployment direction',''],
'TOOLTIP#193' : ['ツールチップ','Tooltip',''],
'TRG#194' : ['対象','Target ',''],
'TRG_DATE#195' : ['対象日','Target date',''],
'TYOTATU_HOUHOU#196' : ['調達方法','Obtain method',''],
'UPDATED_BY#197' : ['更新者','Updated auther',''],
'UPDATED_DATE#198' : ['更新日','Updated date',''],
'UPDATED_PRG_NM#199' : ['更新プログラム名','Updated program',''],
'WARITUKE_HOUKOU#200' : ['割付方向','Assignment direction',''],
'WARITUKE_SIGEN_FLG#201' : ['割付資源フラグ','Assignment flag',''],
'YM#202' : ['年月','YM',''],
'YMPLN_YYYYMM#203' : ['計画月度(指定月以降を更新)','Plan YM (Update after a designated month)',''],
'YMPLN_YYYYMM_SEARCH#204' : ['計画月度','Plan YM',''],
'YUKO_JOKEN_SIKI#205' : ['有効条件式','Vaid condition',''],
'YUSENDO#206' : ['優先度','Priority',''],
'ZAIKO_MAX#207' : ['在庫MAX','Stock MAX',''],
'ZAIKO_MIN#208' : ['在庫MIN','Stock MIN','']
}
for (key in map) {
var keys = key.split('#');
if ( !TALON.getDbConfig().isPostgres() ) {
//PostgreSQL以外
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM SET DISP_NAME = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID LIKE 'ASP_%' " +
" AND COL_NAME = '" + keys[0] + "' " +
" AND DISP_NAME = '" + map[key][now_lang] + "'";
} else {
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM SET DISP_NAME = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID LIKE 'ASP_%' " +
" AND UPPER(COL_NAME) = '" + keys[0] + "' " +
" AND DISP_NAME = '" + map[key][now_lang] + "'";
}
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//グループ名(TLN_M_GENERAL_ITEM)
var map = {
'ASP_ORD0300#0#15' : ['仕様関連','Specification',''],
'ASP_ORD0300#0#23' : ['コメント','Comment',''],
'ASP_ORD0410#0#5' : ['作業情報','Operation Information',''],
'ASP_ORD0410#0#14' : ['計画情報','Plan Information',''],
'ASP_ORD0410#0#21' : ['実績情報','Reported Infomation',''],
'ASP_ORD0410#0#29' : ['追加情報','Other Information',''],
'ASP_ORD0500#0#4' : ['作業情報','Operation Information',''],
'ASP_ORD0500#0#11' : ['計画情報','Plan Information',''],
'ASP_ORD0500#0#16' : ['実績情報','Reported Infomation',''],
'ASP_ORD0500#0#26' : ['追加情報','Other Information','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM SET GROUP_NAME = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND SORT = " + keys[2] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//帳票ファイル名①(TLN_M_GENERAL_ITEM_OPTN)出力ファイル名
var map = {
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#0' : ['作業指示書%SYSDATETIME%','Instruction_%SYSDATETIME%',''],
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#1' : ['作業指示書%SYSDATETIME%.pdf','Instruction_%SYSDATETIME%.pdf','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//帳票ファイル名②(TLN_M_GENERAL_ITEM_OPTN)レイアウトファイル名
var map = {
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#0' : ['ASP_ORD0400.xlsx','ASP_ORD0400_EN.xlsx',''],
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#1' : ['ASP_ORD0400.jasper','ASP_ORD0400_EN.jasper','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//グラフ系列タイトル(TLN_M_GENERAL_ITEM_OPTN)
var map = {
'ASP_PLN1110#1#CHART_AXIS_Y_LABEL_BASE#CHART#0' : ['負荷(%)','Load (%)',''],
'ASP_BGT1120#2#CHART_AXIS_X_LABEL_BASE#CHART#0' : ['工程納期','Process due date',''],
'ASP_BGT1220#1#CHART_AXIS_X_LABEL_BASE#CHART#0' : ['工程納期','Process due date','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//ボタン名①(TLN_M_GENERAL_ITEM_OPTN)+TLN_M_GENERAL_USES
var map = {
'ASP_COP2200#0#ALL#BUTTON_BAT#0' : [' 実 行 ',' E x e c u t e ',''],
'ASP_MST0900#0#ALL#BUTTON_NEXT#0' : ['BOMメンテ','Maintenance Integrated',''],
'ASP_BGT1400#0#ALL#BUTTON_NEXT#1' : ['オーダ・作業','Order / Operration',''],
'ASP_PLN0110#0#ALL#BUTTON_NEXT#1' : ['オーダ・作業','Order / Operration',''],
'ASP_PLN0120#0#ALL#BUTTON_NEXT#1' : ['オーダ・作業','Order / Operration',''],
'ASP_PLN0500#0#ALL#BUTTON_NEXT#1' : ['オーダ・作業','Order / Operration',''],
'ASP_PLN0210#0#ALL#BUTTON_NEXT#2' : ['オーダガント','Order Gantt',''],
'ASP_PLN0220#0#ALL#BUTTON_NEXT#2' : ['オーダガント','Order Gantt',''],
'ASP_PLN0600#0#ALL#BUTTON_NEXT#2' : ['オーダガント','Order Gantt',''],
'ASP_ORD0100#0#ALL#BUTTON_NEXT#0' : ['オーダメンテ','Maintenance Order',''],
'ASP_ORD0400#0#ALL#BUTTON_NEXT#0' : ['オーダメンテ','Maintenance Order',''],
'ASP_BGT1400#0#ALL#BUTTON_NEXT#0' : ['オーダ一覧','Order List',''],
'ASP_PLN0110#0#ALL#BUTTON_NEXT#0' : ['オーダ一覧','Order List',''],
'ASP_PLN0120#0#ALL#BUTTON_NEXT#0' : ['オーダ一覧','Order List',''],
'ASP_PLN0500#0#ALL#BUTTON_NEXT#0' : ['オーダ一覧','Order List',''],
'ASP_ORD0100#0#ALL#BUTTON_NEXT#2' : ['ガントチャート','Ganttchart',''],
'ASP_BGT1110#1#ALL#BUTTON_NEXT#1' : [' グ ラ フ 出 力 ','Graph Output',''],
'ASP_BGT1210#0#ALL#BUTTON_NEXT#0' : [' グ ラ フ 出 力 ','Graph Output',''],
// 'ASP_BGT1210#0#ALL#BUTTON_REPORT#0' : ['グラフ','Graph',''],
'ASP_ORD0100#0#ALL#BUTTON_NEXT#1' : ['作業一覧','Operation List',''],
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#0' : ['作業指示書出力(EXCEL)','Instruction Output (Excel)',''],
'ASP_ORD0400#-1#ALL#BUTTON_REPORT#1' : ['作業指示書出力(PDF)','Instruction Output (PDF)',''],
'ASP_BGT1400#0#ALL#BUTTON_NEXT#2' : ['資源ガント','Resource Gantt',''],
'ASP_PLN0110#0#ALL#BUTTON_NEXT#2' : ['資源ガント','Resource Gantt',''],
'ASP_PLN0120#0#ALL#BUTTON_NEXT#2' : ['資源ガント','Resource Gantt',''],
'ASP_PLN0500#0#ALL#BUTTON_NEXT#2' : ['資源ガント','Resource Gantt',''],
'ASP_ORD0300#1#ALL#BUTTON_NEXT#0' : ['実績入力','Entry Result',''],
'ASP_ORD0400#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0110#0#ALL#BUTTON_NEXT#3' : ['実績入力','Entry Result',''],
'ASP_PLN0120#0#ALL#BUTTON_NEXT#3' : ['実績入力','Entry Result',''],
'ASP_PLN0210#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0220#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0310#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0320#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0500#0#ALL#BUTTON_NEXT#3' : ['実績入力','Entry Result',''],
'ASP_PLN0600#0#ALL#BUTTON_NEXT#1' : ['実績入力','Entry Result',''],
'ASP_PLN0210#0#ALL#BUTTON_NEXT#0' : ['詳 細',' D e t a i l s ',''],
'ASP_PLN0220#0#ALL#BUTTON_NEXT#0' : ['詳 細',' D e t a i l s ',''],
'ASP_PLN0310#0#ALL#BUTTON_NEXT#0' : ['詳 細',' D e t a i l s ',''],
'ASP_PLN0320#0#ALL#BUTTON_NEXT#0' : ['詳 細',' D e t a i l s ',''],
'ASP_PLN0600#0#ALL#BUTTON_NEXT#0' : ['詳 細',' D e t a i l s ',''],
'ASP_ORD0600#0#ALL#BUTTON_NEXT#0' : ['入力','Entry',''],
'ASP_PLN0110#-1#ALL#BUTTON_AJAX#0' : ['非同期','Asynchronous',''],
'ASP_PLN0110#-1#ALL#BUTTON_AJAX_CLIANT_JAVASCRIPT#0' : ['非同期','Asynchronous',''],
'ASP_PLN0210#-1#ALL#BUTTON_AJAX#0' : ['非同期','Asynchronous',''],
'ASP_PLN0210#-1#ALL#BUTTON_AJAX_CLIANT_JAVASCRIPT#0' : ['非同期','Asynchronous',''],
'ASP_PLN0310#-1#ALL#BUTTON_AJAX#0' : ['非同期','Asynchronous',''],
'ASP_PLN0310#-1#ALL#BUTTON_AJAX_CLIANT_JAVASCRIPT#0' : ['非同期','Asynchronous',''],
'ASP_BGT1110#1#ALL#BUTTON_NEXT#0' : [' 品 目 別 ',' By Item ',''],
'ASP_PLN1110#0#ALL#BUTTON_NEXT#0' : [' 負 荷 を 見 る ',' See the load ','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
//ボタンの初期表示設定の更新
var sql = "" +
"UPDATE TLN_M_GENERAL_USES SET KEY_CODE = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND OPTN = 'BUTTON' " +
" AND KEY_CODE = '" + map[key][now_lang] + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//ボタン名②(TLN_M_GENERAL_ITEM_OPTN)+TLN_M_GENERAL_POSITION
var map = {
'ASP_SYS0010#0#ALL#BUTTON_BAT#3' : ['サンプルデータ削除','Sample Data Delete',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#2' : ['サンプルデータ登録','Sample Data Entry',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#1' : ['セットアップ・パッチ','Setup patch processing ',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#0' : ['セットアップ・初期化','Setup / initialization processing ',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#4' : ['メニュー構成データ登録','Menu Data Entry',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#5' : ['日本語に変換','Language change (Japanese)',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#6' : ['英語に変換','Language change (English)',''],
'ASP_SYS0010#0#ALL#BUTTON_BAT#7' : ['中国語に変換','Language change (Chinese)','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
//ボタンのフリーレイアウト定義の更新
var sql = "" +
"UPDATE TLN_M_GENERAL_POSITION SET NAME = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND CHR1 = 'BUTTON' " +
" AND NAME = '" + map[key][now_lang] + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//フリーレイアウト(TLN_M_GENERAL_POSITION)
var map = {
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0#5' : ['初期化、もしくは初回のインストール','Initialization or initial install',''],
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0#6' : ['メニュー構成','Menu structure',''],
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0#18' : ['2回目以降のインストール','Second or later install',''],
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0#19' : ['言語変更','Language change',''],
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0_34#0' : ['FUNC_CHK','FUNC_CHK',''],
'ASP_SYS0010#BLOCK#BASE_INFO#0_0_0_34#1' : [' Viewを再構築する',' Rebuild View','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_GENERAL_POSITION SET NAME = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND SCOPE = '" + keys[1] + "' " +
" AND ATTR_KBN = '" + keys[2] + "' " +
" AND POS = '" + keys[3] + "' " +
" AND SORT = " + keys[4] + " ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//汎用マスタ:識別コード名
var map = {
'ASP_ALL_SEARCH' : ['全てを検索する','Search all',''],
'ASP_BACK_COLOR' : ['背景色設定','Background color',''],
'ASP_BACK_COLOR_FUNC' : ['背景色設定機能','Background color setting function',''],
'ASP_BASE_DATE' : ['基準日付データ','Date data',''],
'ASP_BOMMNT_AVGKIKAN' : ['製造BOM時間メンテ過去平均期間','Integrated, average time ',''],
'ASP_BOMMNT_STDEV' : ['製造BOM時間メンテ実績除外','Integrated, exclusion from reported',''],
'ASP_CHECKBOX_ONE' : ['対象チェックボックス','Target check box',''],
'ASP_DEL_FLG' : ['論理削除フラグ','Delete flag',''],
'ASP_DEL_FLG_NONE' : ['論理削除フラグ','Delete flag (checkbox)',''],
'ASP_ITEM_AUTO_HOJU_FLG' : ['ASPROVA品目自動補充フラグ','Auto-replenish flag',''],
'ASP_ITEM_SYUBETU' : ['ASPROVA品目種別','Item type',''],
'ASP_ITEM_SYUBETU_ALL' : ['ASPROVA品目種別','Item type (all)',''],
'ASP_ITEM_SYUBETU_I' : ['品目種別中間品','Intermediate item',''],
'ASP_KASANARI_HOUHOU' : ['ASPROVA重なり方法','Time constraint method',''],
'ASP_LOAD_INFO_KBN' : ['負荷グラフ対象資源区分','Load graph target',''],
'ASP_NOKI_OKURE_NONE' : ['納期遅れフラグ','Due date delay flag',''],
'ASP_ORDER_KBN' : ['ASPROVAオーダ区分','Order class',''],
'ASP_ORDER_STATUS' : ['ASPROVAオーダステータス','Order status',''],
'ASP_ORDER_SYUBETU' : ['ASPROVAオーダ種別','Order type',''],
'ASP_PROJECTID' : ['プロジェクトID','Project id',''],
'ASP_SAGYO_STATUS' : ['ASPROVA作業ステータス','Operation status',''],
'ASP_SASIZU_SYUBETU' : ['ASPROVA指図種別','Instruction type',''],
'ASP_SEARCH_KBN_ITEM' : ['検索品目区分','Item class (search)',''],
'ASP_SEARCH_KBN_SIGEN' : ['検索資源区分','Resource class (search)',''],
'ASP_SIGEN_KBN' : ['ASPROVA資源区分','Resource class',''],
'ASP_SIGEN_SEIYAKU' : ['ASPROVA資源量制約','Resource quantity constraints',''],
'ASP_SIGEN_SYUBETU' : ['ASPROVA資源種別','Resource type',''],
'ASP_TENKAI_END' : ['展開末端','Deployment end',''],
'ASP_TENKAI_HOUKOU' : ['展開方向','Deployment direction',''],
'ASP_TYOTATU_HOUHOU' : ['ASPROVA品目調達方法','Obtain method',''],
'ASP_WARITUKE_SIGEN_FLG' : ['ASPROVA割付け資源量フラグ','Assignment flag',''],
'ASP_YUSENDO_NVL' : ['優先度未設定時','When no priority is set',''],
'ASP_TOOLTIP_TITLE' : ['ツールチップタイトル','Tooltip title','']
}
for (key in map) {
var sql = "" +
"UPDATE TLN_M_HANYO_CODE_MAIN SET SIKIBETU_NM = '" + map[key][to_lang] + "' " +
"WHERE SIKIBETU_CODE = '" + key + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//汎用マスタ:DSP1
var map = {
'ASP_ALL_SEARCH#1' : ['全てを検索','Search all',''],
'ASP_BACK_COLOR#009487' : ['標準表示色16(#009487)','Background color16 (#009487)',''],
'ASP_BACK_COLOR#00B04E' : ['標準表示色17(#00B04E)','Background color17 (#00B04E)',''],
'ASP_BACK_COLOR#2DDD7B' : ['標準表示色26(#2DDD7B)','Background color26 (#2DDD7B)',''],
'ASP_BACK_COLOR#32C6B9' : ['標準表示色19(#32C6B9)','Background color19 (#32C6B9)',''],
'ASP_BACK_COLOR#5AAE72' : ['標準表示色14(#5AAE72)','Background color14 (#5AAE72)',''],
'ASP_BACK_COLOR#64F8EB' : ['標準表示色5(#64F8EB)','Background color5 (#64F8EB)',''],
'ASP_BACK_COLOR#64FFB2' : ['標準表示色2(#64FFB2)','Background color2 (#64FFB2)',''],
'ASP_BACK_COLOR#8080FF' : ['標準表示色3(#8080FF)','Background color3 (#8080FF)',''],
'ASP_BACK_COLOR#8585DC' : ['標準表示色27(#8585DC)','Background color27 (#8585DC)',''],
'ASP_BACK_COLOR#8F69D0' : ['標準表示色15(#8F69D0)','Background color15 (#8F69D0)',''],
'ASP_BACK_COLOR#8F83A8' : ['標準表示色12(#8F83A8)','Background color12 (#8F83A8)',''],
'ASP_BACK_COLOR#9B9490' : ['標準表示色20(#9B9490)','Background color20 (#9B9490)',''],
'ASP_BACK_COLOR#A8C0C1' : ['標準表示色11(#A8C0C1)','Background color11 (#A8C0C1)',''],
'ASP_BACK_COLOR#ADADFF' : ['標準表示色9(#ADADFF)','Background color9 (#ADADFF)',''],
'ASP_BACK_COLOR#B7ABD0' : ['標準表示色31(#B7ABD0)','Background color31 (#B7ABD0)',''],
'ASP_BACK_COLOR#BA9BA7' : ['標準表示色30(#BA9BA7)','Background color30 (#BA9BA7)',''],
'ASP_BACK_COLOR#BFB939' : ['標準表示色22(#BFB939)','Background color22 (#BFB939)',''],
'ASP_BACK_COLOR#C59777' : ['標準表示色7(#C59777)','Background color7 (#C59777)',''],
'ASP_BACK_COLOR#C5A0FF' : ['標準表示色23(#C5A0FF)','Background color23 (#C5A0FF)',''],
'ASP_BACK_COLOR#C6D2AF' : ['標準表示色29(#C6D2AF)','Background color29 (#C6D2AF)',''],
'ASP_BACK_COLOR#C8C1BD' : ['標準表示色32(#C8C1BD)','Background color32 (#C8C1BD)',''],
'ASP_BACK_COLOR#CAAF66' : ['標準表示色24(#CAAF66)','Background color24 (#CAAF66)',''],
'ASP_BACK_COLOR#CBFB47' : ['標準表示色8(#CBFB47)','Background color8 (#CBFB47)',''],
'ASP_BACK_COLOR#CEA8B6' : ['標準表示色13(#CEA8B6)','Background color13 (#CEA8B6)',''],
'ASP_BACK_COLOR#CFB17D' : ['標準表示色28(#CFB17D)','Background color28 (#CFB17D)',''],
'ASP_BACK_COLOR#E8BA9A' : ['標準表示色21(#E8BA9A)','Background color21 (#E8BA9A)',''],
'ASP_BACK_COLOR#ECE666' : ['標準表示色4(#ECE666)','Background color4 (#ECE666)',''],
'ASP_BACK_COLOR#F05728' : ['標準表示色25(#F05728)','Background color25 (#F05728)',''],
'ASP_BACK_COLOR#F280FF' : ['標準表示色6(#F280FF)','Background color6 (#F280FF)',''],
'ASP_BACK_COLOR#FD96BA' : ['標準表示色18(#FD96BA)','Background color18 (#FD96BA)',''],
'ASP_BACK_COLOR#FF895A' : ['標準表示色1(#FF895A)','Background color1 (#FF895A)',''],
'ASP_BACK_COLOR#FFBB8C' : ['標準表示色10(#FFBB8C)','Background color10 (#FFBB8C)',''],
'ASP_BACK_COLOR_FUNC#1' : ['オーダガントチャート','Order Ganttchart',''],
'ASP_BACK_COLOR_FUNC#2' : ['資源ガントチャート','Resource Ganttchart',''],
'ASP_BACK_COLOR_FUNC#3' : ['作業スケジュール','Operation Schedule',''],
'ASP_BASE_DATE#1' : ['01','01',''],
'ASP_BASE_DATE#10' : ['10','10',''],
'ASP_BASE_DATE#11' : ['11','11',''],
'ASP_BASE_DATE#12' : ['12','12',''],
'ASP_BASE_DATE#13' : ['13','13',''],
'ASP_BASE_DATE#14' : ['14','14',''],
'ASP_BASE_DATE#15' : ['15','15',''],
'ASP_BASE_DATE#16' : ['16','16',''],
'ASP_BASE_DATE#17' : ['17','17',''],
'ASP_BASE_DATE#18' : ['18','18',''],
'ASP_BASE_DATE#19' : ['19','19',''],
'ASP_BASE_DATE#2' : ['02','02',''],
'ASP_BASE_DATE#20' : ['20','20',''],
'ASP_BASE_DATE#21' : ['21','21',''],
'ASP_BASE_DATE#22' : ['22','22',''],
'ASP_BASE_DATE#23' : ['23','23',''],
'ASP_BASE_DATE#24' : ['24','24',''],
'ASP_BASE_DATE#25' : ['25','25',''],
'ASP_BASE_DATE#26' : ['26','26',''],
'ASP_BASE_DATE#27' : ['27','27',''],
'ASP_BASE_DATE#28' : ['28','28',''],
'ASP_BASE_DATE#29' : ['29','29',''],
'ASP_BASE_DATE#3' : ['03','03',''],
'ASP_BASE_DATE#30' : ['30','30',''],
'ASP_BASE_DATE#31' : ['31','31',''],
'ASP_BASE_DATE#4' : ['04','04',''],
'ASP_BASE_DATE#5' : ['05','05',''],
'ASP_BASE_DATE#6' : ['06','06',''],
'ASP_BASE_DATE#7' : ['07','07',''],
'ASP_BASE_DATE#8' : ['08','08',''],
'ASP_BASE_DATE#9' : ['09','09',''],
'ASP_BOMMNT_AVGKIKAN#-1' : ['1か月','1 month',''],
'ASP_BOMMNT_AVGKIKAN#-3' : ['3か月','3 months',''],
'ASP_BOMMNT_AVGKIKAN#-6' : ['6か月','6 months',''],
'ASP_BOMMNT_STDEV#1' : ['68.26%','68.26%',''],
'ASP_BOMMNT_STDEV#2' : ['95.44%','95.44%',''],
'ASP_BOMMNT_STDEV#3' : ['99.73%','99.73%',''],
'ASP_CHECKBOX_ONE#1' : [' ',' ',''],
'ASP_DEL_FLG#1' : ['削除','Delete',''],
'ASP_DEL_FLG_NONE#1' : [' ',' ',''],
'ASP_ITEM_AUTO_HOJU_FLG#0' : ['いいえ','No',''],
'ASP_ITEM_AUTO_HOJU_FLG#1' : ['はい','Yes',''],
'ASP_ITEM_AUTO_HOJU_FLG#2' : ['はい(1対1生産)','Yes (1 to 1 production)',''],
'ASP_ITEM_AUTO_HOJU_FLG#3' : ['はい(在庫+1対1生産)','Yes (stock + 1 to 1 production)',''],
'ASP_ITEM_AUTO_HOJU_FLG#4' : ['はい(需給調整1対1生産)','Yes (1 supply and demand adjustment to 1 production)',''],
'ASP_ITEM_SYUBETU#H' : ['半製品','Manufactured part',''],
'ASP_ITEM_SYUBETU#M' : ['原材料','Raw material',''],
'ASP_ITEM_SYUBETU#P' : ['製品','Finished item',''],
'ASP_ITEM_SYUBETU#U' : ['購買品','Purchased part',''],
'ASP_ITEM_SYUBETU_ALL#H' : ['半製品','Manufactured part',''],
'ASP_ITEM_SYUBETU_ALL#I' : ['中間品','Intermediate item',''],
'ASP_ITEM_SYUBETU_ALL#M' : ['原材料','Raw material',''],
'ASP_ITEM_SYUBETU_ALL#P' : ['製品','Finished item',''],
'ASP_ITEM_SYUBETU_ALL#U' : ['購買品','Purchased part',''],
'ASP_ITEM_SYUBETU_I#1' : ['含む','Include',''],
'ASP_KASANARI_HOUHOU#EES' : ['EES','EES',''],
'ASP_KASANARI_HOUHOU#ES' : ['ES','ES',''],
'ASP_KASANARI_HOUHOU#ESE' : ['ESE','ESE',''],
'ASP_KASANARI_HOUHOU#ESSEE' : ['ESSEE','ESSEE',''],
'ASP_KASANARI_HOUHOU#SS' : ['SS','SS',''],
'ASP_KASANARI_HOUHOU#SSEE' : ['SSEE','SSEE',''],
'ASP_KASANARI_HOUHOU#SSEEE' : ['SSEEE','SSEEE',''],
'ASP_LOAD_INFO_KBN#0' : ['非対象','Target',''],
'ASP_LOAD_INFO_KBN#1' : ['対象','Not targeted',''],
'ASP_NOKI_OKURE_NONE#1' : [' ',' ',''],
'ASP_ORDER_KBN#0' : ['登録','Registered order',''],
'ASP_ORDER_KBN#1' : ['補充','Replenishment order',''],
'ASP_ORDER_STATUS#B' : ['完了','Completed',''],
'ASP_ORDER_STATUS#T' : ['着手済','Started',''],
'ASP_ORDER_STATUS#X' : ['未着手','Not started',''],
'ASP_ORDER_SYUBETU#I' : ['在庫(絶対量)','Inventory (absolute)',''],
'ASP_ORDER_SYUBETU#J' : ['在庫(増減量)','Inventory (fluctuation)',''],
'ASP_ORDER_SYUBETU#M' : ['製造','Manufacturing order',''],
'ASP_ORDER_SYUBETU#P' : ['購買','Purchase order',''],
'ASP_ORDER_SYUBETU#S' : ['受注','Sales order',''],
'ASP_PROJECTID#TFA5' : ['TFA5','TFA5',''],
'ASP_SAGYO_STATUS#A' : ['計画済み','Scheduled',''],
'ASP_SAGYO_STATUS#B' : ['完了','Completed',''],
'ASP_SAGYO_STATUS#D' : ['確定','Frozen',''],
'ASP_SAGYO_STATUS#I' : ['指示済み','Released',''],
'ASP_SAGYO_STATUS#T' : ['着手済み','Started',''],
'ASP_SASIZU_SYUBETU#I' : ['I:入力指図','Input instruction',''],
'ASP_SASIZU_SYUBETU#O' : ['O:出力指図','Use instruction',''],
'ASP_SASIZU_SYUBETU#U' : ['U:使用指図','Output instruction',''],
'ASP_SEARCH_KBN_ITEM#0' : ['品目番号','item code',''],
'ASP_SEARCH_KBN_ITEM#1' : ['品目グループ','item groups',''],
'ASP_SEARCH_KBN_SIGEN#0' : ['資源コード','Resource code',''],
'ASP_SEARCH_KBN_SIGEN#1' : ['資源グループ','Resource groups',''],
'ASP_SIGEN_KBN#F' : ['炉資源(任意仕様)','Furnace resource (Any spec)',''],
'ASP_SIGEN_KBN#F1' : ['炉資源(仕様1)','Furnace resource (Spec 1)',''],
'ASP_SIGEN_KBN#F2' : ['炉資源(仕様2)','Furnace resource (Spec 2)',''],
'ASP_SIGEN_KBN#F3' : ['炉資源(仕様3)','Furnace resource (Spec 3)',''],
'ASP_SIGEN_KBN#F4' : ['炉資源(仕様4)','Furnace resource (Spec 4)',''],
'ASP_SIGEN_KBN#M' : ['多重資源','Multiplex resource',''],
'ASP_SIGEN_KBN#S' : ['単純資源','Simple resource',''],
'ASP_SIGEN_SEIYAKU#N' : ['制約なし','Not constrained',''],
'ASP_SIGEN_SEIYAKU#R' : ['制約あり','Constrained',''],
'ASP_SIGEN_SEIYAKU#V' : ['資源量に応じて','According to resource quantity',''],
'ASP_SIGEN_SYUBETU#II' : ['在庫(デフォルト)','Inventory(default)',''],
'ASP_SIGEN_SYUBETU#M' : ['主資源','Main resource',''],
'ASP_SIGEN_SYUBETU#PI' : ['購買(デフォルト)','Purchase(default)',''],
'ASP_SIGEN_SYUBETU#S' : ['副資源','Sub resource',''],
'ASP_SIGEN_SYUBETU#SI' : ['受注(デフォルト)','Sales(default)',''],
'ASP_TENKAI_END#0' : ['末端以外','Not end',''],
'ASP_TENKAI_END#1' : ['末端','End',''],
'ASP_TENKAI_HOUKOU#0' : ['正展開','Positive development',''],
'ASP_TENKAI_HOUKOU#1' : ['逆展開','Reverse development',''],
'ASP_TYOTATU_HOUHOU#IM' : ['内製優先','Prefer to produce',''],
'ASP_TYOTATU_HOUHOU#IP' : ['購買優先','Prefer to purchase',''],
'ASP_TYOTATU_HOUHOU#M' : ['内製','Produce',''],
'ASP_TYOTATU_HOUHOU#P' : ['購買','Purchase',''],
'ASP_WARITUKE_SIGEN_FLG#0' : ['通常','Normal',''],
'ASP_WARITUKE_SIGEN_FLG#1' : ['製造数量に比例させる','Proportionate to production quantity',''],
'ASP_YUSENDO_NVL#SORT_VALUE' : ['ソート用代替値','Alternative value',''],
'ASP_TOOLTIP_TITLE#1' : ['<オーダ>','[ Order ]',''],
'ASP_TOOLTIP_TITLE#2' : ['<納 期>','[ Due date ]',''],
'ASP_TOOLTIP_TITLE#3' : ['<作 業>','[ Operation ]',''],
'ASP_TOOLTIP_TITLE#4' : ['<品 目>','[ Item ]',''],
'ASP_TOOLTIP_TITLE#5' : ['<製造数量>','[ Production quantity ]',''],
'ASP_TOOLTIP_TITLE#6' : ['<開始日時>','[ Start time ]',''],
'ASP_TOOLTIP_TITLE#7' : ['<終了日時>','[ End time ]',''],
'ASP_TOOLTIP_TITLE#8' : ['<段取り時間:分>','[ Processing time ]',''],
'ASP_TOOLTIP_TITLE#9' : ['<製造時間:分>','[ Production time ]','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_HANYO_CODE_MAIN SET DSP1 = '" + map[key][to_lang] + "' " +
"WHERE SIKIBETU_CODE = '" + keys[0] + "' " +
" AND KEY_CODE = '" + keys[1] + "' ";
//TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//汎用マスタ:DSP2
var map = {
'ASP_ORDER_SYUBETU#I' : ['在庫','Inventory',''],
'ASP_ORDER_SYUBETU#J' : ['在庫','Inventory',''],
'ASP_ORDER_SYUBETU#M' : ['製造','Manufacturing order',''],
'ASP_ORDER_SYUBETU#P' : ['購買','Purchase order',''],
'ASP_ORDER_SYUBETU#S' : ['受注','Sales order',''],
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_HANYO_CODE_MAIN SET DSP2 = '" + map[key][to_lang] + "' " +
"WHERE SIKIBETU_CODE = '" + keys[0] + "' " +
" AND KEY_CODE = '" + keys[1] + "' ";
//TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//メニュー:メニューグループ
var map = {
'systemASP_BGT' : ['予実分析','Budget and Results Analysis',''],
'systemASP_MBL' : ['スマートフォン実績入力','Entry Operation Result (Smartphone)',''],
'systemASP_MST' : ['マスタ関連','Master Maintenance',''],
'systemASP_ORD' : ['オーダ・作業','Order / Operation',''],
'systemASP_PLN' : ['計画分析','Plan Analysis',''],
'systemASP_SYS' : ['システム管理','System Management','']
}
for (key in map) {
var sql = "" +
"UPDATE TLN_M_AUTHORITY SET FUNC_NM = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ATH_ID = '" + key + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//メニュー:メニューグループ
var map = {
'systemTLN_TFA//systemASP_ORD#ASP_ORD0100R' : ['オーダ一覧照会','Inquiry Order List ',''],
'systemTLN_TFA//systemASP_ORD#ASP_ORD0100U' : ['オーダ一覧メンテナンス','Maintenance Order List ',''],
'systemTLN_TFA//systemASP_ORD#ASP_ORD0400U' : ['作業一覧・指示書発行','Operation List / Instruction ',''],
'systemTLN_TFA//systemASP_ORD#ASP_ORD0300U' : ['オーダ・作業メンテナンス','Maintenance Order / Operation List',''],
'systemTLN_TFA//systemASP_ORD#ASP_ORD0700U' : ['作業実績一括入力','Entry Operation Result (Bulkupdate)',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0110U' : ['オーダガントチャート','Order Ganttchart',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0120U' : ['オーダガントチャート(更新)','Order Ganttchart (Entry)',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0210U' : ['資源ガントチャート','Resource Ganttchart',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0220U' : ['資源ガントチャート(更新)','Resource Ganttchart (Entry)',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0310U' : ['作業スケジュールカレンダー','Operation Schedule',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0320U' : ['作業スケジュールカレンダー(更新)','Operation Schedule (Entry)',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0400U' : ['作業調整一括取消','Cancel Operation Change Data',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0700U' : ['ガントチャート・カレンダーカラー変更','Ganttchart / Schedule Color Ghange',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0500U' : ['複数計画比較 オーダガントチャート','Multiple Plan Order Ganttchart',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN0600U' : ['複数計画比較 資源ガントチャート','Multiple Plan Resource Ganttchart',''],
'systemTLN_TFA//systemASP_PLN#ASP_PLN1110U' : ['負荷グラフ照会','Inquiry Load Graph',''],
'systemTLN_TFA//systemASP_BGT#ASP_BGT1110U' : ['資源別予実照会','Budget and Results by Resource',''],
'systemTLN_TFA//systemASP_BGT#ASP_BGT1210U' : ['資源・品目別予実照会','Budget and Results by Item',''],
'systemTLN_TFA//systemASP_BGT#ASP_BGT1400U' : ['予実オーダガントチャート','Budget and Results by Order Gantt',''],
'systemTLN_TFA//systemASP_BGT#ASP_COP2200U' : ['月間計画作成','Monthly Planning',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0800U' : ['資源マスタメンテナンス','Maintenance Reource Master',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0700U' : ['工程マスタメンテナンス','Maintenance Process Master',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0600U' : ['品目マスタメンテナンス','Maintenance Item Master',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0100U' : ['製造BOMマスタメンテナンス','Maintenance Integrated Master',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0400U' : ['製造BOM段取り製造時間メンテナンス','Maintenance SetupTime Master',''],
'systemTLN_TFA//systemASP_MST#ASP_MST0900U' : ['構成照会','Inquiry Configuration',''],
'systemTLN_TFA//systemASP_MBL#ASP_ORD0600U' : ['作業照会(スマートフォン)','Operation List (Smartphone)',''],
'systemTLN_TFA//systemASP_MBL#ASP_ORD0610U' : ['実績入力(スマートフォン)','Entry Operation Result (Smartphone)',''],
'systemTLN_TFA//systemASP_SYS#ASP_SYS0010U' : ['セットアップ・初期化','System Setup / Initialization','']
}
for (key in map) {
var keys = key.split('#');
var sql = "" +
"UPDATE TLN_M_FUNCTION SET FUNC_NM = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ATH_ID = '" + keys[0] + "' " +
" AND FUNC_ID = '" + keys[1] + "' ";
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
//機能設定:入力許可メッセージ(TLN_M_GENERAL_ITEM_OPTN)
//※PostgreSQL注意(COL_NAME)
var map = {
'ASP_ORD0100#0#ORDER_SU#MATCH_PATTERN#0' : ['受注オーダ、製造オーダ、購買オーダには 0より大きい数値を入力して下さい。','Please enter values greater than 0 for "Sales order", "Purchase order" and "Manufacturing order".',' '],
'ASP_ORD0500#0#END_DATE#MATCH_PATTERN#0' : ['完了の場合、実績終了日時を入力して下さい。','Please enter "Reported end time" in case of "Completed".',' '],
'ASP_ORD0500#0#MAE_DANDORI_END_DATE#MATCH_PATTERN#0' : ['前段取り終了日時の入力時、前段取り開始日時を入力してください。','When entering "Setup end time", please enter the "Setup start time".',' '],
'ASP_ORD0500#0#MAE_DANDORI_START_DATE#MATCH_PATTERN#0' : ['着手済みの場合、前段取り開始日時もしくは実績開始日時を入力して下さい。(必須)','Please enter "Setup start time" or "Reported start time" in case of "Started". (required)',' '],
'ASP_ORD0500#0#SEIZO_END_DATE#MATCH_PATTERN#0' : ['完了の場合、実績終了日時を入力して下さい。(必須)','Please enter "Reported end time" in case of "Completed". (required)',' '],
'ASP_ORD0500#0#SEIZO_START_DATE#MATCH_PATTERN#0' : ['着手済みの場合、前段取り開始日時もしくは実績開始日時を入力して下さい。(必須)','Please enter "Setup start time" or "Reported start time" in case of "Started". (required)',' '],
'ASP_ORD0500#0#SEIZO_SU#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績数量を入力して下さい。','Please enter "Reported qty" in case of "Started" or "Completed".',' '],
'ASP_ORD0500#0#SIGEN_CODE#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績資源コードを入力して下さい。','Please enter "Reported Resource" in case of "Started" or "Completed".',' '],
'ASP_ORD0500#0#START_DATE#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績開始日時を入力して下さい。','Please enter "Reported start time" in case of "Started" or "Completed".',' '],
'ASP_ORD0700#0#END_DATE#MATCH_PATTERN#0' : ['完了の場合、実績終了日時を入力して下さい。','Please enter "Reported end time" in case of "Completed". ',' '],
'ASP_ORD0700#0#MAE_DANDORI_END_DATE#MATCH_PATTERN#0' : ['前段取り終了日時入力時は、前段取り開始日時を入力してください。','When entering "Setup end time", please enter the "Setup start time".',' '],
'ASP_ORD0700#0#MAE_DANDORI_START_DATE#MATCH_PATTERN#0' : ['着手済みの場合、前段取り開始日時もしくは実績開始日時を入力して下さい。(必須)','Please enter "Setup start time" or "Reported start time" in case of "Started". (required)',' '],
'ASP_ORD0700#0#SEIZO_END_DATE#MATCH_PATTERN#0' : ['完了の場合、実績終了日時を入力して下さい。(必須)','Please enter "Reported end time" in case of "Completed". (required)',' '],
'ASP_ORD0700#0#SEIZO_START_DATE#MATCH_PATTERN#0' : ['着手済みの場合、前段取り開始日時もしくは実績開始日時を入力して下さい。(必須)','Please enter "Setup start time" or "Reported start time" in case of "Started". (required)',' '],
'ASP_ORD0700#0#SEIZO_SU#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績数量を入力して下さい。','Please enter "Reported qty" in case of "Started" or "Completed".',' '],
'ASP_ORD0700#0#SIGEN_CODE#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績資源コードを入力して下さい。','Please enter "Reported Resource" in case of "Started" or "Completed".',' '],
'ASP_ORD0700#0#START_DATE#MATCH_PATTERN#0' : ['着手済み、完了の場合、実績開始日時を入力して下さい。','Please enter "Reported start time" in case of "Started" or "Completed".',' ']
}
for (key in map) {
var keys = key.split('#');
if ( !TALON.getDbConfig().isPostgres() ) {
//PostgreSQL以外
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND COL_NAME = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
} else {
var sql = "" +
"UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = '" + map[key][to_lang] + "' " +
"WHERE FUNC_ID = '" + keys[0] + "' " +
" AND FUNC_SEQ = " + keys[1] + " " +
" AND UPPER(COL_NAME) = '" + keys[2] + "' " +
" AND FUNC_KBN = '" + keys[3] + "' " +
" AND OPT_SORT = " + keys[4] + " ";
}
// * TALON.addMsg( "★" + sql );
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
// ----------------------------------------
//汎用マスタの言語を更新
var sql = "" +
"UPDATE TLN_M_HANYO_CODE_MAIN SET DSP1 = '" + to_lang + "' " +
"WHERE SIKIBETU_CODE = 'ASP_LANGUAGE' " +
" AND KEY_CODE = 'LANG' ";
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
function create_himo_data_relation() {
//
table_exists_drop('ASP_WK_SAGYO_INFO_MAE');
//
table_exists_drop('ASP_WK_SAGYO_INFO_ATO');
//Oracle
//--------------------------------------------------------------------------------
if ( TALON.getDbConfig().isOra() ) {
// if ( !table_exists("ASP_WK_SAGYO_INFO_MAE") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_MAE( PROJECTID VARCHAR2(200) , ORDER_CODE_MY VARCHAR2(200) , SAGYO_CODE_MY VARCHAR2(200) , MAX_END_DATE DATE ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_MAE ADD ( CONSTRAINT PK_ASP_WK_SAGYO_INFO_MAE PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") USING INDEX ) " +
"");
// }
// if ( !table_exists("ASP_WK_SAGYO_INFO_ATO") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_ATO( PROJECTID VARCHAR2(200) , ORDER_CODE_MY VARCHAR2(200) , SAGYO_CODE_MY VARCHAR2(200) , MIN_START_DATE DATE ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_ATO ADD ( CONSTRAINT PK_ASP_WK_SAGYO_INFO_ATO PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") USING INDEX ) " +
"");
// }
};
//MySQL
//--------------------------------------------------------------------------------
if ( TALON.getDbConfig().isMy() ) {
// if ( !table_exists("ASP_WK_SAGYO_INFO_MAE") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_MAE( PROJECTID varchar(200) , ORDER_CODE_MY varchar(200) , SAGYO_CODE_MY varchar(200) , MAX_END_DATE datetime ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_MAE ADD CONSTRAINT PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
// if ( !table_exists("ASP_WK_SAGYO_INFO_ATO") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_ATO( PROJECTID varchar(200) , ORDER_CODE_MY varchar(200) , SAGYO_CODE_MY varchar(200) , MIN_START_DATE datetime ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_ATO ADD CONSTRAINT PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
};
//SQLServer
//--------------------------------------------------------------------------------
if ( TALON.getDbConfig().isMssql() ) {
// if ( !table_exists("ASP_WK_SAGYO_INFO_MAE") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_MAE( PROJECTID NVARCHAR(200) NOT NULL , ORDER_CODE_MY NVARCHAR(200) NOT NULL , SAGYO_CODE_MY NVARCHAR(200) NOT NULL , MAX_END_DATE DATETIME ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_MAE ADD CONSTRAINT PK_ASP_WK_SAGYO_INFO_MAE PRIMARY KEY NONCLUSTERED ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
// if ( !table_exists("ASP_WK_SAGYO_INFO_ATO") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_ATO( PROJECTID NVARCHAR(200) NOT NULL , ORDER_CODE_MY NVARCHAR(200) NOT NULL , SAGYO_CODE_MY NVARCHAR(200) NOT NULL , MIN_START_DATE DATETIME ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_ATO ADD CONSTRAINT PK_ASP_WK_SAGYO_INFO_ATO PRIMARY KEY NONCLUSTERED ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
};
//PostgreSQL
//--------------------------------------------------------------------------------
if ( TALON.getDbConfig().isPostgres() ) {
// if ( !table_exists("ASP_WK_SAGYO_INFO_MAE") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_MAE( PROJECTID character varying(200) , ORDER_CODE_MY character varying(200) , SAGYO_CODE_MY character varying(200) , MAX_END_DATE timestamp(6) ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_MAE ADD CONSTRAINT PK_ASP_WK_SAGYO_INFO_MAE PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
// if ( !table_exists("ASP_WK_SAGYO_INFO_ATO") ) {
executeSQL( "CREATE TABLE ASP_WK_SAGYO_INFO_ATO( PROJECTID character varying(200) , ORDER_CODE_MY character varying(200) , SAGYO_CODE_MY character varying(200) , MIN_START_DATE timestamp(6) ) ");
executeSQL(
"ALTER TABLE ASP_WK_SAGYO_INFO_ATO ADD CONSTRAINT PK_ASP_WK_SAGYO_INFO_ATO PRIMARY KEY ( " +
"PROJECTID, " +
"ORDER_CODE_MY, " +
"SAGYO_CODE_MY " +
") " +
"");
// }
};
}
≣ サーバJS ライブラリST_COMMON 要員シフト管理共通JavaScript 364字
/**********************************
*
* 要員シフト管理用共通JavaSctipt
*
**********************************/
//文字列の日付情報(YYYY/MM/DD)をJavaのDate型に変換して戻す。
function tln_string_to_date(val) {
y = parseInt(val.split("/")[0]) - 1900;
m = parseInt(val.split("/")[1]) - 1;
d = parseInt(val.split("/")[2]);
var date = new java.util.Date(y,m,d);
return date;
}≣ サーバJS ライブラリTALON_FUNCTION_COMMON_BK TALON機能設計書出力 共通ライブラリ 39964字
// TALON_FUNCTION_COMMON: TALON機能設計書出力 共通サーバ側JS
// LIBRARY_CODE: 0JSENGINE / TYPE: server-side common library
//
// 提供API:
// TFC.getLabelBundle(lang) Java ResourceBundle 取得 (ja/en/zh_CN/...)
// TFC.lbl(bundle, key, fallback) キー→翻訳テキスト
// TFC.escapeHtml(s) HTML エスケープ
// TFC.escapeMd(s) Markdown エスケープ
// TFC.escapeAttr(s) HTML 属性値エスケープ (& < " ' のみ)
// TFC.formatSql(s) SQL 整形 (将来用、現状は trim のみ)
// TFC.appKbnLabel(appKbn, lang) APP_KBN → "固定検索条件"等
// TFC.funcKbnInfo(funcKbn) FUNC_KBN → {section, labelKey, table} (辞書)
// TFC.toLocale(lang) lang 文字列を java.util.Locale へ変換
// TFC.HTML_HEAD / TFC.HTML_TAIL 自己完結HTMLの head/tail 生成
// TFC.htmlSection(title, body, opts) <details>セクション生成
// TFC.tabBadge(isOn, count, lang) タブ on/off バッジ HTML
// TFC.zip(entries) {name: bytes/string} → ZIP バイト列 (java.util.zip)
(function (global) {
'use strict';
var ResourceBundle = Java.type('java.util.ResourceBundle');
var Locale = Java.type('java.util.Locale');
var ByteArrayOutputStream = Java.type('java.io.ByteArrayOutputStream');
var ZipOutputStream = Java.type('java.util.zip.ZipOutputStream');
var ZipEntry = Java.type('java.util.zip.ZipEntry');
var JString = Java.type('java.lang.String');
var Charset = Java.type('java.nio.charset.Charset');
var TFC = {};
// ============================================================
// 言語・ラベル
// ============================================================
TFC.toLocale = function (lang) {
if (!lang) return Locale.JAPANESE;
var s = String(lang);
if (s.indexOf('_') > 0) {
var p = s.split('_');
return new Locale(p[0], p[1]);
}
if (s === 'ja') return Locale.JAPANESE;
if (s === 'en') return Locale.ENGLISH;
return new Locale(s);
};
var _bundleCache = {};
TFC.getLabelBundle = function (lang) {
var key = lang || 'ja';
if (!_bundleCache[key]) {
_bundleCache[key] = ResourceBundle.getBundle('general', TFC.toLocale(key));
}
return _bundleCache[key];
};
TFC.lbl = function (bundle, key, fallback) {
try {
return String(bundle.getString(key));
} catch (e) {
return fallback != null ? fallback : key;
}
};
// ============================================================
// エスケープ
// ============================================================
TFC.escapeHtml = function (s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
TFC.escapeAttr = function (s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
TFC.escapeMd = function (s) {
if (s == null) return '';
// Markdown で意味を持つ文字のうち、テキスト中で誤動作しやすいものをエスケープ
return String(s).replace(/([\\`*_{}\[\]()#+\-!|>])/g, '\\$1');
};
TFC.formatSql = function (s) {
if (s == null) return '';
return String(s).replace(/\r\n/g, '\n').replace(/\t/g, ' ').replace(/\n+$/, '');
};
// ============================================================
// APP_KBN ラベル ([TALON-DB設定マスタ.md] 出典)
// ============================================================
var APP_KBN_MAP = {
ja: { STD: '固定検索条件', FREE: 'フリー検索条件', SUB: '検索子画面', BAT: '検索ボタン無し' },
en: { STD: 'Fixed search condition', FREE: 'Free search condition', SUB: 'Sub search screen', BAT: 'No search button' }
};
TFC.appKbnLabel = function (appKbn, lang) {
var l = (lang && APP_KBN_MAP[lang]) ? lang : 'ja';
var m = APP_KBN_MAP[l];
return (m && m[appKbn]) || appKbn || '';
};
// ============================================================
// 項目情報の値マッピング
// ============================================================
var COMPONENT_MAP = {
'0': 'TEXT (テキスト)', '1': 'COMBO (ドロップダウン)', '2': 'CHECKBOX',
'3': 'RADIO', '4': 'TEXTAREA', '5': 'CHECK_FLG (フラグチェック)',
'6': 'PASSWORD', '7': 'HIDDEN', '8': 'LABEL (固定表示)',
'9': 'SUGGEST', '10': 'BARCODE', '11': 'IMAGE', '12': 'FILE',
'13': 'CLOB_TEXT', '14': 'TOGGLE', '15': 'COLOR_PICKER',
'16': 'DATE_PICKER', '17': 'TIME_PICKER', '18': 'DATETIME_PICKER'
};
TFC.componentLabel = function (val) {
var v = val == null ? '' : String(val);
return COMPONENT_MAP[v] || v;
};
var DATA_TYPE_MAP = {
'VARCHAR2': '文字列 (VARCHAR2)', 'CHAR': '文字列固定 (CHAR)',
'NUMBER': '数値 (NUMBER)', 'INTEGER': '整数 (INTEGER)',
'DATE': '日付 (DATE)', 'TIMESTAMP': '日時 (TIMESTAMP)',
'CLOB': 'CLOB (大量文字)', 'BLOB': 'BLOB (バイナリ)',
'BOOLEAN': '真偽 (BOOLEAN)'
};
TFC.dataTypeLabel = function (val) {
var v = val == null ? '' : String(val).toUpperCase();
return DATA_TYPE_MAP[v] || v;
};
TFC.flgLabel = function (val) {
var v = val == null ? '' : String(val);
if (v === '1') return '○';
if (v === '0' || v === '') return '';
return v;
};
// ============================================================
// FUNC_KBN 辞書 (Phase 3: 全208項目, TALON-DB設定マスタ.md から自動生成)
// 生成スクリプト: AI開発/scripts/build_func_kbn_dict.py
//
// section: 'app-application' | 'app-report' | 'app-othernext' | 'app-ajax'
// | 'block-item' | 'block-detail' | 'block-detail-cal'
// | 'block-report' | 'block-proc' | 'block-othernext'
// | 'block-fileio' | 'block-otherfunc' | 'block-other'
// | 'block-chart-general' | 'block-chart-x' | 'block-chart-y'
// | 'block-chart-y2' | 'block-chart-series'
// | 'free-layout' | 'auth-menu' | 'other'
// ============================================================
var FUNC_KBN_DICT = {
'KEY_COL_BLOCK': { section: 'app-application', labelJa: '機能タイプ', table: 'TLN_M_GENERAL_APP' },
'OPEN_WINDOW_MODE': { section: 'app-application', labelJa: '起動Window状態', table: 'TLN_M_GENERAL_APP' },
'WIN_H': { section: 'app-application', labelJa: 'Window高さ', table: 'TLN_M_GENERAL_APP' },
'WIN_W': { section: 'app-application', labelJa: 'Window幅', table: 'TLN_M_GENERAL_APP' },
'WIN_POS_X': { section: 'app-application', labelJa: '表示位置 横', table: 'TLN_M_GENERAL_APP' },
'WIN_POS_Y': { section: 'app-application', labelJa: '表示位置 縦', table: 'TLN_M_GENERAL_APP' },
'WIN_POS': { section: 'app-application', labelJa: '表示位置', table: 'TLN_M_GENERAL_APP' },
'IS_NOT_WIN_RESIZE': { section: 'app-application', labelJa: 'Windowサイズ変更不可', table: 'TLN_M_GENERAL_APP' },
'IS_ON_RELOAD_ORIGIN_WIN_SIZE': { section: 'app-application', labelJa: '再描画時、設定したWindow位置サイズに戻す', table: 'TLN_M_GENERAL_APP' },
'IS_WIN_OPENER_CLOSED': { section: 'app-application', labelJa: 'Window終了オプション', table: 'TLN_M_GENERAL_APP' },
'TAB_MENU_NAME': { section: 'app-application', labelJa: 'ブロック', table: 'TLN_M_GENERAL_APP' },
'CHART': { section: 'app-application', labelJa: 'ブロック', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CONDTN_CNT': { section: 'app-application', labelJa: '検索条件項目数', table: 'TLN_M_GENERAL_APP' },
'COND_SAVE_HDN_FLG': { section: 'app-application', labelJa: '検索条件保存', table: 'TLN_M_GENERAL_APP' },
'IS_CONDITION_TITLE_OFF': { section: 'app-application', labelJa: '検索条件タイトル', table: 'TLN_M_GENERAL_APP' },
'BACK_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'CLEAR_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'PDF_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'EXCEL_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'SEARCH_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_CND': { section: 'app-application', labelJa: '確定ボタン', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_NAME_DISP_FORMULA': { section: 'app-application', labelJa: '確定ボタン', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_MESSAGE': { section: 'app-application', labelJa: '確定終了メッセージ', table: 'TLN_M_GENERAL_APP' },
'IS_EXECUTE_MESSAGE_HIDDEN': { section: 'app-application', labelJa: '確定終了メッセージ', table: 'TLN_M_GENERAL_APP' },
'IS_EXECUTE_CONFIRM': { section: 'app-application', labelJa: '確定ボタン確認ダイアログ', table: 'TLN_M_GENERAL_APP' },
'EXE_DISP_INIT_FLG': { section: 'app-application', labelJa: '確定後再表示オプション', table: 'TLN_M_GENERAL_APP' },
'EXE_TARGET_ONLY_FLG_NO_SEARCH': { section: 'app-application', labelJa: '確定後再表示オプション', table: 'TLN_M_GENERAL_APP' },
'EXE_DISP_TARGET_ONLY_FLG': { section: 'app-application', labelJa: '確定後再表示オプション', table: 'TLN_M_GENERAL_APP' },
'IS_EXE_AUTH': { section: 'app-application', labelJa: '確定時認証', table: 'TLN_M_GENERAL_APP' },
'SEND_MAIL': { section: 'app-application', labelJa: '確定後のメール送信', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEND_MAIL_': { section: 'app-application', labelJa: '確定後のメール送信', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVA_SCRIPT_ENGINE': { section: 'app-application', labelJa: 'DB検索JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PL_SQL_NAME_SEARCH': { section: 'app-application', labelJa: 'DB検索プロシージャ名', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_SEARCH_AFTER': { section: 'app-application', labelJa: 'DB検索プロシージャ名', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME': { section: 'app-application', labelJa: 'プロシージャ名', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_AFTER': { section: 'app-application', labelJa: 'プロシージャ名', table: 'TLN_M_GENERAL_APP' },
'ACCESS_DB': { section: 'app-application', labelJa: 'DB接続先', table: 'TLN_M_GENERAL_APP' },
'JAVA_SCRIPT': { section: 'app-application', labelJa: 'Client-side JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSS': { section: 'app-application', labelJa: 'CSS', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JOIN': { section: 'app-application', labelJa: '結合項目', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_DSP_POS': { section: 'app-application', labelJa: 'ボタン位置移動', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_REPORT': { section: 'app-report', labelJa: 'EXCEL', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'ALL_OPT': { section: 'app-report', labelJa: 'EXCEL', table: 'BUTTON_REPORT' },
'BUTTON_NEXT': { section: 'app-othernext', labelJa: '機能画面設定', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX': { section: 'app-ajax', labelJa: 'ボタン名', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX_CLIENT_JAVASCRIPT': { section: 'app-ajax', labelJa: '再表示ブロック', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX_': { section: 'app-ajax', labelJa: 'DB検索前JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CR_FLG_SEARCH': { section: 'block-item', labelJa: '検索改行', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'REQUIRED_SEARCH': { section: 'block-item', labelJa: '検索必須', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'IS_DB_NOT_REGIST': { section: 'block-item', labelJa: 'DB更新無し', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TABLE_LAYOUT': { section: 'block-item', labelJa: 'ROW SPAN', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TABLE_TITLE_LAYOUT': { section: 'block-item', labelJa: 'タイトルROW SPAN', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEARCH_METHOD': { section: 'block-item', labelJa: '検索方式', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'DISP_POS': { section: 'block-item', labelJa: '表示位置', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TAB_INDEX_SEARCH': { section: 'block-item', labelJa: 'Tab index(検索)', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TAB_INDEX': { section: 'block-item', labelJa: 'Tab index', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CAMMA_OFF': { section: 'block-item', labelJa: 'カンマ編集無し', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'ZERO_SPLIT': { section: 'block-item', labelJa: '小数点ゼロ埋め', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'ALL_SELECT_CHECK': { section: 'block-item', labelJa: 'コンポーネント', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TATE_CHECK': { section: 'block-item', labelJa: 'コンポーネント', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OPTION_LIST_FUNC_ID': { section: 'block-item', labelJa: 'オプションリスト機能ID', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OPTION_LIST_SEARCH': { section: 'block-item', labelJa: 'オプションリスト機能ID', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CLASS_CODE': { section: 'block-item', labelJa: '階層コード/レベル', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'NEST': { section: 'block-item', labelJa: '階層コード/レベル', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INPUT_CONDITION': { section: 'block-item', labelJa: '入力許可パターン', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MATCH_PATTERN': { section: 'block-item', labelJa: '入力チェックパターン', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEARCH_FUNC_ID': { section: 'block-item', labelJa: '検索子画面', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUB_SEARCH': { section: 'block-item', labelJa: '検索子画面', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUB_BTN_HDN': { section: 'block-item', labelJa: '子画面非表示', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MASTER_CHECK': { section: 'block-item', labelJa: 'マスタチェック', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LOOK_UP_FUNC_ID': { section: 'block-item', labelJa: 'LOOKUP', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LOOK_UP': { section: 'block-item', labelJa: 'LOOKUP', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FOCUS_OUT_JAVASCRIPT': { section: 'block-item', labelJa: 'FOCUS OUT', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FLAT_TEXT': { section: 'block-item', labelJa: '値保持', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUGGEST_FUNC_ID': { section: 'block-item', labelJa: 'SUGGEST', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUGGEST': { section: 'block-item', labelJa: 'SUGGEST', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PRINTING_UPDATE': { section: 'block-item', labelJa: '印刷時更新項目', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FORE_COLOR': { section: 'block-item', labelJa: '文字色', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BACK_COLOR': { section: 'block-item', labelJa: '背景色', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INIT_VALUE_TEXT': { section: 'block-item', labelJa: '検索条件初期値', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INIT_VALUE': { section: 'block-item', labelJa: '検索条件初期値', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'REGIST_VALUE': { section: 'block-item', labelJa: 'DB設定式', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FIX_FORMULA': { section: 'block-item', labelJa: '固定条件式', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SAIBAN_SIKIBETU_CODE': { section: 'block-item', labelJa: '採番名', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SERIAL_NUMBER_VAL': { section: 'block-item', labelJa: 'シリアル番号加算値', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVASCRIPT': { section: 'block-item', labelJa: 'JavaScript呼出ボタン', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVASCRIPT_ENGINE': { section: 'block-item', labelJa: 'JavaScript呼出ボタン', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BARCODE_FORMAT': { section: 'block-item', labelJa: 'EXCEL帳票', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'THUMBNAIL_SIZE': { section: 'block-item', labelJa: 'サムネイル・バーコードサイズ', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'IMG_UPLOAD_SIZE': { section: 'block-item', labelJa: 'アップロードファイルサイズ', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'DRILL_DOWN': { section: 'block-item', labelJa: 'ドリルダウンレベル項目', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'HDN_LIST_SORT': { section: 'block-item', labelJa: '明細ソート無し', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TITLE_NOTE': { section: 'block-item', labelJa: 'タイトルツールチップ', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MAX_LINE_COUNT': { section: 'block-detail', labelJa: '画面最大行数', table: 'TLN_M_GENERAL_APP' },
'MAX_LINE_COUNT_EXCEL': { section: 'block-detail', labelJa: '標準Excel出力最大行数', table: 'TLN_M_GENERAL_APP' },
'MAX_LINE_CNT_EXCEL_UPDATE': { section: 'block-detail', labelJa: '更新Excel出力最大行数', table: 'TLN_M_GENERAL_APP' },
'ADD_LINE_VAL_INIT': { section: 'block-detail', labelJa: '追加行の初期値', table: 'TLN_M_GENERAL_APP' },
'STD_EXCEL_EXT': { section: 'block-detail', labelJa: '標準Excel拡張子', table: 'TLN_M_GENERAL_APP' },
'LIST_PAGE_ROWS': { section: 'block-detail', labelJa: '初期ページ内行数', table: 'TLN_M_GENERAL_APP' },
'LIST_PAGE_DROPDOWN': { section: 'block-detail', labelJa: '改頁行数選択リスト', table: 'TLN_M_GENERAL_APP' },
'SPACE_HEIGHT': { section: 'block-detail', labelJa: '表示高さ', table: 'TLN_M_GENERAL_APP' },
'IS_VERTICAL_LAYOUT': { section: 'block-detail', labelJa: '行見出しレイアウト', table: 'TLN_M_GENERAL_APP' },
'HDN_PAGER_FLG': { section: 'block-detail', labelJa: '改ページしない', table: 'TLN_M_GENERAL_APP' },
'BLOCK_NAME_HDN_FLG': { section: 'block-detail', labelJa: 'ブロック名フィールドを非表示', table: 'TLN_M_GENERAL_APP' },
'IS_SEARCH_NOTFOUND_MSG_HDN': { section: 'block-detail', labelJa: '検索結果0件メッセージを非表示', table: 'TLN_M_GENERAL_APP' },
'IS_CLOSE_SWITCH': { section: 'block-detail', labelJa: '開閉表示状態', table: 'TLN_M_GENERAL_APP' },
'IS_LIST_ROW_SELECT': { section: 'block-detail', labelJa: '明細行の編集方式', table: 'TLN_M_GENERAL_APP' },
'IS_LIST_FIXED': { section: 'block-detail', labelJa: '明細列の固定', table: 'TLN_M_GENERAL_APP' },
'EXCELUPDATE_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'VIEW_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'COL_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', table: 'TLN_M_GENERAL_APP' },
'EXCELUPDATE_BTN_DISABLED_FLG': { section: 'block-detail', labelJa: '検索前ボタンの非活性', table: 'TLN_M_GENERAL_APP' },
'INSERT_FLG': { section: 'block-detail', labelJa: '処理権限', table: 'TLN_M_GENERAL_APP' },
'UPDATE_FLG': { section: 'block-detail', labelJa: '処理権限', table: 'TLN_M_GENERAL_APP' },
'DELETE_FLG': { section: 'block-detail', labelJa: '処理権限', table: 'TLN_M_GENERAL_APP' },
'EXCLUSIVE_CONTROL_FLG': { section: 'block-detail', labelJa: '確定時オプション', table: 'TLN_M_GENERAL_APP' },
'ALL_REG_FLG': { section: 'block-detail', labelJa: '確定時オプション', table: 'TLN_M_GENERAL_APP' },
'IS_USE_SEARCH_RESULT_REPORT': { section: 'block-detail', labelJa: '確定時オプション', table: 'TLN_M_GENERAL_APP' },
'IS_USE_SEARCH_RESULT_MAIL': { section: 'block-detail', labelJa: '確定時オプション', table: 'TLN_M_GENERAL_APP' },
'PLSQL_PARAM_COL': { section: 'block-detail', labelJa: 'プロシージャ名', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LISTSELECT_BTN_CND': { section: 'block-detail', labelJa: '参照ボタン', table: 'TLN_M_GENERAL_APP' },
'LISTSEL_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '参照ボタン', table: 'TLN_M_GENERAL_APP' },
'COPY_DL_BTN_CND': { section: 'block-detail', labelJa: '複写ボタン', table: 'TLN_M_GENERAL_APP' },
'COPY_DL_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '複写ボタン', table: 'TLN_M_GENERAL_APP' },
'ADDLINE_DL_BTN_CND': { section: 'block-detail', labelJa: '行追加ボタン', table: 'TLN_M_GENERAL_APP' },
'ADDLINE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '行追加ボタン', table: 'TLN_M_GENERAL_APP' },
'DELETE_BTN_CND': { section: 'block-detail', labelJa: '削除ボタン', table: 'TLN_M_GENERAL_APP' },
'DELETE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '削除ボタン', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CODE_': { section: 'block-detail', labelJa: '行文字色', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_KBN_': { section: 'block-detail', labelJa: '行文字色', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CND_': { section: 'block-detail', labelJa: '行文字色', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_CODE_': { section: 'block-detail', labelJa: '行背景色', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_KBN_': { section: 'block-detail', labelJa: '行背景色', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_CND_': { section: 'block-detail', labelJa: '行背景色', table: 'TLN_M_GENERAL_APP' },
'SAVE_BTN_CND': { section: 'block-detail', labelJa: '保存ボタン', table: 'TLN_M_GENERAL_APP' },
'SAVE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '保存ボタン', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TITLE_COL': { section: 'block-detail', labelJa: 'タスクコード', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_GRID_TOP': { section: 'block-detail', labelJa: '時間グリッドのスクロールTOP', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_FROM_DATE_COL': { section: 'block-detail', labelJa: '開始日時', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TO_DATE_COL': { section: 'block-detail', labelJa: '終了日時', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_START_WEEK': { section: 'block-detail', labelJa: '開始曜日', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_INIT_SCALE': { section: 'block-detail', labelJa: '描画期間初期値', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_MONTH': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_WEEK': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_DAY': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', table: 'TLN_M_GENERAL_APP' },
'IS_ALL_DAY_CHECK_ON': { section: 'block-detail', labelJa: 'All Day チェックボックス状態', table: 'TLN_M_GENERAL_APP' },
'CALENDAR_SIKIBETU_CODE': { section: 'block-detail', labelJa: 'カレンダー識別コード', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_UPDATE_CONFIRM': { section: 'block-detail', labelJa: 'イベントバーの変更時確認', table: 'TLN_M_GENERAL_APP' },
'IS_SCHEDULE_UIWAIT_LOCK': { section: 'block-detail', labelJa: '処理中ロック', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TITLE_DISP_COL': { section: 'block-detail', labelJa: 'タスク表示名', table: 'TLN_M_GENERAL_APP' },
'IS_TASK_GROUING_DISP': { section: 'block-detail', labelJa: 'タスク名の全種表示', table: 'TLN_M_GENERAL_APP' },
'TASK_AREA_WIDTH': { section: 'block-detail', labelJa: 'タスク領域幅', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_EVENT_TEXT_COL': { section: 'block-detail', labelJa: 'イベント内容項目', table: 'TLN_M_GENERAL_APP' },
'IS_FIT_EVENT_BAR_MAX_WIDTH': { section: 'block-detail', labelJa: 'イベント内容項目', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_EVENT_TOOLTIP_COL': { section: 'block-detail', labelJa: 'ツールチップ項目', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_UNIQUE_COL': { section: 'block-detail', labelJa: '関係線KEY項目', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_CONNECT_FROM_COL': { section: 'block-detail', labelJa: '関係線FROM', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_CONNECT_TO_COL': { section: 'block-detail', labelJa: '関係線TO', table: 'TLN_M_GENERAL_APP' },
'LABEL_DSP_CNT': { section: 'block-detail', labelJa: '日時ラベル最大表示数', table: 'TLN_M_GENERAL_APP' },
'IS_GRID_SNAP_OFF': { section: 'block-detail', labelJa: 'イベントバーのグリッドスナップ', table: 'TLN_M_GENERAL_APP' },
'IS_ST_ED_TOOLTIP_HIDDEN': { section: 'block-detail', labelJa: '開始-終了日時ツールチップ', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_MOUSE_ALLOW_RESIZING': { section: 'block-detail', labelJa: 'イベントバーのマウス操作', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_MOUSE_ALLOW_MOVING': { section: 'block-detail', labelJa: 'イベントバーのマウス操作', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_HOUR_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_FROM_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_LIMIT_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_DAY_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_DAY_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_WEEK_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_WEEK_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_MONTH_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_MONTH_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_QUARTERLY_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_QTR_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_HALF_YEAR_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_HALF_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_YEAR_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_ONE_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_YEARS_BTN': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_YEARS_GRID_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'GANTT_YEARS_INIT_VAL': { section: 'block-detail', labelJa: '描画期間の制御エリア', table: 'TLN_M_GENERAL_APP' },
'BUTTON_BAT': { section: 'block-proc', labelJa: 'JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_BAT_CLIENT_JAVASCRIPT': { section: 'block-proc', labelJa: 'JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_BAT_': { section: 'block-proc', labelJa: 'プロシージャ', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_NEXT_': { section: 'block-othernext', labelJa: '設定(機能ID指定あり)', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON': { section: 'block-fileio', labelJa: 'ファイル出力', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_OPTION': { section: 'block-fileio', labelJa: 'ファイル出力', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_FILE': { section: 'block-fileio', labelJa: 'ファイル出力', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_COL': { section: 'block-fileio', labelJa: 'ファイル出力', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON': { section: 'block-fileio', labelJa: 'DB登録', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_OPTION': { section: 'block-fileio', labelJa: 'DB登録', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_FILE': { section: 'block-fileio', labelJa: 'DB登録', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_COL': { section: 'block-fileio', labelJa: 'DB登録', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OTHER_FUNC': { section: 'block-otherfunc', labelJa: '式', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OTHER_FUNC_': { section: 'block-otherfunc', labelJa: '項目設定', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'UPDATE_TABLE': { section: 'block-other', labelJa: 'SELECT式', table: 'TLN_M_GENERAL_APP' },
'OTHER_BLOCK_FUNC': { section: 'block-other', labelJa: '他ブロック', table: 'TLN_M_GENERAL_APP' },
'CHART_MARK': { section: 'block-chart-series', labelJa: 'マーカー', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FUNC_TOP_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_HEAD': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'CONDITION_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_TOP': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'RESULT_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_BTM': { section: 'free-layout', labelJa: '機能実行画面デザイン', table: 'TLN_M_GENERAL_POSITION' },
'BLOCK': { section: 'free-layout', labelJa: 'ブロックデザイン(明細)', table: 'TLN_M_GENERAL_POSITION' },
'CONDITION': { section: 'free-layout', labelJa: 'ブロックデザイン(検索条件)', table: 'TLN_M_GENERAL_POSITION' },
// === DB スキャンで未対応だった追加分 (TLN_M_GENERAL_APP) ===
'EXECUTE_BTN_DISP_NAME': { section: 'app-application', labelJa: '確定ボタン表示名', table: 'TLN_M_GENERAL_APP' },
'HELP_LINK_NM': { section: 'app-application', labelJa: 'ヘルプリンク表示名', table: 'TLN_M_GENERAL_APP' },
'HELP_URL': { section: 'app-application', labelJa: 'ヘルプURL', table: 'TLN_M_GENERAL_APP' },
'PLOT_BTN_CND': { section: 'app-application', labelJa: 'プロットボタン表示条件式', table: 'TLN_M_GENERAL_APP' },
// === DB スキャンで未対応だった追加分 (TLN_M_GENERAL_ITEM_OPTN) ===
// ※ BUTTON_AJAX_<N>, BUTTON_BAT_<N>, BUTTON_NEXT_<N>, OTHER_FUNC_<N>, SEND_MAIL_<N> 系は
// _<digits> サフィックスのフォールバック解決でカバーされる (TFC.funcKbnInfo 参照)
'BUTTON_AJAX_CLIANT_JAVASCRIPT': { section: 'app-ajax', labelJa: '非同期通信ボタン Client-side JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_LIST_OPT': { section: 'block-otherfunc', labelJa: 'LIST明細選択ボタンオプション', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PLOT': { section: 'block-detail', labelJa: 'グラフ プロット設定', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PLOT_COL': { section: 'block-detail', labelJa: 'グラフ プロット項目設定', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PLOT_COL_MARKER_STYLE': { section: 'block-detail', labelJa: 'グラフ プロット項目 マーカースタイル', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PLOT_COL_PIE_OPTION': { section: 'block-detail', labelJa: 'グラフ プロット項目 円グラフオプション', table: 'TLN_M_GENERAL_ITEM_OPTN' },
// === DB設定マスタ.csv (talon-docs) との突合で判明した追加分 ===
// 機能タブ アプリケーション (FUNC_SEQ=-1)
'SEARCH_FLG': { section: 'app-application', labelJa: '検索ボタン表示', table: 'TLN_M_GENERAL_APP' },
'CLEAR_FLG': { section: 'app-application', labelJa: 'クリアボタン表示', table: 'TLN_M_GENERAL_APP' },
'EXCEL_OUT_FLG': { section: 'app-application', labelJa: 'Excel出力ボタン表示', table: 'TLN_M_GENERAL_APP' },
'PDF_OUT_FLG': { section: 'app-application', labelJa: 'PDF出力ボタン表示', table: 'TLN_M_GENERAL_APP' },
// ブロック設定 詳細 (FUNC_SEQ != -1) — _<N> サフィックス連番系の基底キーとして登録
'BACK_COLOR_TR_CODE': { section: 'block-detail', labelJa: '行背景色 動的キー', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CODE': { section: 'block-detail', labelJa: '行文字色 動的キー', table: 'TLN_M_GENERAL_APP' },
'GANTT_REF_UPDATE_TABLE': { section: 'block-detail', labelJa: 'GANTT 参照更新テーブル', table: 'TLN_M_GENERAL_APP' },
// ブロック 検索呼出 (DLプロシージャ)
'PL_SQL_NAME_DL': { section: 'block-proc', labelJa: '検索前プロシージャ (引出)', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_AFTER_DL': { section: 'block-proc', labelJa: '検索後プロシージャ (引出)', table: 'TLN_M_GENERAL_APP' },
// 項目情報 (TLN_M_GENERAL_ITEM_OPTN)
'ZERO_INT': { section: 'block-item', labelJa: 'ゼロ値ハイフン表示', table: 'TLN_M_GENERAL_ITEM_OPTN' },
};
// FUNC_KBN は同種設定が複数登録されると `_<N>` 連番サフィックスが付くことがある
// 例: BUTTON_NEXT, BUTTON_NEXT_0, BUTTON_NEXT_1, ... (同じ FUNC_KBN 系列を別レコードとして保持)
// この場合、辞書に基底キーがあればフォールバックで該当エントリを返す
function _resolveBaseKbn(funcKbn) {
if (!funcKbn) return null;
if (FUNC_KBN_DICT[funcKbn]) return FUNC_KBN_DICT[funcKbn];
// _<digits> 末尾を削って再検索
var m = funcKbn.match(/^(.+?)_(\d+)$/);
if (m && FUNC_KBN_DICT[m[1]]) return FUNC_KBN_DICT[m[1]];
return null;
}
TFC.funcKbnInfo = function (funcKbn) {
return _resolveBaseKbn(funcKbn);
};
TFC.isKnownFuncKbn = function (funcKbn) {
return _resolveBaseKbn(funcKbn) != null;
};
// ============================================================
// HTML テンプレート部品
// ============================================================
TFC.htmlHead = function (titleText, lang) {
var l = lang || 'ja';
var t = TFC.escapeHtml(titleText);
return '<!DOCTYPE html>\n' +
'<html lang="' + l + '">\n' +
'<head>\n' +
'<meta charset="UTF-8">\n' +
'<meta name="viewport" content="width=device-width,initial-scale=1.0">\n' +
'<title>' + t + '</title>\n' +
'<style>' + TFC.CSS + '</style>\n' +
'</head>\n<body>\n';
};
TFC.htmlTail = function () {
return '\n<script>' + TFC.JS_TAIL + '</script>\n</body>\n</html>\n';
};
TFC.tabBadge = function (isOn, count, lang) {
if (isOn) {
var on = (lang === 'en') ? '● set (' + count + ')' : '● 設定あり (' + count + '件)';
return '<span class="tab-status tab-status-on">' + on + '</span>';
}
var off = (lang === 'en') ? '○ none' : '○ 設定なし';
return '<span class="tab-status tab-status-off">' + off + '</span>';
};
TFC.htmlSection = function (titleHtml, bodyHtml, classes) {
var c = classes ? ' ' + classes : '';
return '<details class="screen-section' + c + '">\n' +
'<summary>' + titleHtml + '</summary>\n' +
'<div class="section-body">\n' + (bodyHtml || '') + '\n</div>\n' +
'</details>\n';
};
// 仕様書 §6.1: DOMContentLoaded で全 details を強制 close
TFC.JS_TAIL =
"document.addEventListener('DOMContentLoaded',function(){" +
"document.querySelectorAll('details').forEach(function(d){d.open=false;});" +
"});" +
"function tfcAll(open){document.querySelectorAll('details').forEach(function(d){d.open=open;});}" +
"function tfcCardOnly(){document.querySelectorAll('details.func-card,details.shared-card').forEach(function(d){d.open=true;});" +
"document.querySelectorAll('details.func-card details, details.shared-card details').forEach(function(d){d.open=false;});}" +
"function tfcOnOnly(){document.querySelectorAll('details').forEach(function(d){d.open=true;});" +
"document.querySelectorAll('details.tab-off').forEach(function(d){d.open=false;});}";
// 仕様書 §8 の色パレットを採用
TFC.CSS = "body{font-family:'Segoe UI',Meiryo,sans-serif;background:#f1f5f9;color:#1e293b;margin:0;padding:0 12px 32px;line-height:1.55}" +
"h1{font-size:1.5em;margin:18px 0 8px}" +
".meta{font-size:.9em;color:#475569;margin-bottom:6px}" +
".legend{font-size:.85em;color:#475569;margin:6px 0}" +
".controls{position:sticky;top:0;background:#fff;padding:8px;border-bottom:1px solid #cbd5e1;z-index:10;margin-bottom:12px}" +
".controls button{margin-right:6px;padding:4px 10px;font-size:.9em;cursor:pointer;border:1px solid #94a3b8;background:#f8fafc;border-radius:3px}" +
".controls button:hover{background:#e2e8f0}" +
"details.func-card{border:2px solid #cbd5e1;border-radius:6px;background:#fff;margin:14px 0;padding:6px 10px}" +
"details.func-card[open]{border-color:#7dd3fc}" +
"details.func-card>summary{font-weight:bold;font-size:1.1em;cursor:pointer;padding:4px 0}" +
"details.shared-card{border:2px solid #f59e0b;border-radius:6px;background:#fef3c7;margin:14px 0;padding:6px 10px}" +
"details.block-card{border:1px solid #7dd3fc;border-radius:4px;margin:8px 0;padding:4px 8px;background:#f0f9ff}" +
"details.screen-section{border:1px solid #e2e8f0;border-radius:3px;margin:6px 0;padding:4px 8px;background:#f8fafc}" +
"details.screen-section.tab-on{border-color:#86efac;background:#f0fdf4}" +
"details.screen-section.tab-off{border-color:#e2e8f0;background:#f8fafc;opacity:.85}" +
"details>summary{cursor:pointer;outline:none}" +
".tab-status{font-size:.85em;margin-left:8px}" +
".tab-status-on{color:#15803d}" +
".tab-status-off{color:#94a3b8}" +
".section-body{padding:6px 0 6px 12px}" +
"table.kv{border-collapse:collapse;margin:4px 0;width:auto}" +
"table.kv th,table.kv td{border:1px solid #cbd5e1;padding:3px 8px;font-size:.92em;text-align:left;vertical-align:top}" +
"table.kv th{background:#f1f5f9;color:#475569;white-space:nowrap;min-width:160px}" +
"table.kv td.val{background:#fff}" +
"table.kv-compact{table-layout:auto;width:auto}" +
"table.kv-compact th{min-width:0;padding:2px 6px;white-space:nowrap;font-size:.85em}" +
"table.kv-compact td{padding:2px 6px;font-size:.88em;white-space:nowrap;max-width:280px;overflow:hidden;text-overflow:ellipsis}" +
"table.kv-compact td:hover{overflow:visible;white-space:normal;background:#fef3c7}" +
"code,pre{font-family:Consolas,'Courier New',monospace}" +
"pre.sql-code,pre.js-code{background:#0f172a;color:#a5f3fc;padding:8px 10px;border-radius:4px;overflow:auto;font-size:.85em;margin:4px 0}" +
".kbn{display:inline-block;background:#fef3c7;color:#b45309;padding:1px 6px;border-radius:3px;font-size:.82em;font-family:Consolas,monospace}" +
".unclassified{border:2px dashed #f87171;background:#fef2f2;padding:8px 12px;border-radius:4px;margin:10px 0}" +
".unclassified summary{color:#b91c1c;font-weight:bold}";
// ============================================================
// ZIP 出力 (Java util.zip)
// ============================================================
// entries: [{name: 'a.html', content: 'string'}, {name: 'b.md', content: 'string'}]
// 戻り値: byte[] (Java)
TFC.zip = function (entries) {
var baos = new ByteArrayOutputStream();
var zos = new ZipOutputStream(baos, Charset.forName('UTF-8'));
try {
for (var i = 0; i < entries.length; i++) {
var e = entries[i];
zos.putNextEntry(new ZipEntry(e.name));
var bytes = new JString(e.content).getBytes(Charset.forName('UTF-8'));
zos.write(bytes, 0, bytes.length);
zos.closeEntry();
}
} finally {
zos.close();
}
return baos.toByteArray();
};
// ============================================================
// Markdown テンプレート部品
// ============================================================
TFC.mdHeader = function (title) {
return '# ' + (title || '') + '\n\n';
};
TFC.mdSection = function (level, heading, body) {
var hashes = '';
for (var i = 0; i < (level || 2); i++) hashes += '#';
return hashes + ' ' + (heading || '') + '\n\n' + (body || '') + '\n';
};
TFC.mdKvTable = function (rows) {
// rows: [[key, val], ...]
if (!rows || rows.length === 0) return '';
var s = '| 項目 | 値 |\n|------|----|\n';
for (var i = 0; i < rows.length; i++) {
var k = TFC.escapeMd(rows[i][0]);
var v = TFC.escapeMd(rows[i][1] != null ? String(rows[i][1]) : '');
s += '| ' + k + ' | ' + v + ' |\n';
}
return s + '\n';
};
TFC.mdCodeBlock = function (lang, code) {
return '```' + (lang || '') + '\n' + (code || '') + '\n```\n\n';
};
// ============================================================
// ユーティリティ
// ============================================================
TFC.s = function (v) { return v == null ? '' : String(v); };
TFC.isEmpty = function (v) { return v == null || String(v).length === 0; };
TFC.coalesce = function () {
for (var i = 0; i < arguments.length; i++) {
if (!TFC.isEmpty(arguments[i])) return arguments[i];
}
return '';
};
// export
global.TFC = TFC;
return TFC;
})(this);
≣ サーバJS ライブラリTLN_AI_DEV_DEMO_DATE_UTIL TLN_AI_DEV_DEMO_DATE_UTIL 3906字
/**
* TLN_AI_DEV_DEMO_DATE_UTIL
*
* TALON画面の入力値をSQL実行用の日付型へ変換する共通関数です。
* JavaScriptエンジン APIマニュアル 11.2 JavaScript日付変換ユーティリティ の内容に沿っています。
*/
/**
* ロケールごとの日付フォーマット定義です。
*/
var DATE_PATTERN_BY_LOCALE = {
'en_us': 'MM/dd/yyyy',
'en-us': 'MM/dd/yyyy',
'en_gb': 'dd/MM/yyyy',
'en-gb': 'dd/MM/yyyy'
};
/**
* 標準の日付フォーマットです。
*/
var DEFAULT_DATE_PATTERN = 'yyyy/MM/dd';
/**
* 画面入力値を java.sql.Date に変換します。
*
* ・java.util.Date の場合:そのまま java.sql.Date 化
* ・文字列の場合:ユーザーロケールに応じた形式で parse
*
* 対応例:
* ・ja / ja_JP:yyyy/MM/dd
* ・en_US :MM/dd/yyyy
* ・en_GB :dd/MM/yyyy
*
* @param {*} value 画面入力値
* @returns {java.sql.Date|null} SQL日付
* @throws {java.text.ParseException} 文字列 value がユーザーロケールの日付形式に一致しない場合、または不正な日付の場合
*/
function toSqlDate(value) {
if (value == null || value === '') {
return null;
}
var SqlDate = Java.type('java.sql.Date');
if (value.getTime) {
return new SqlDate(value.getTime());
}
var utilDate = parseDate(
value,
getDatePatternByLocale()
);
return new SqlDate(utilDate.getTime());
}
/**
* 画面入力値を java.sql.Timestamp に変換します。
*
* ・java.util.Date の場合:そのまま Timestamp 化
* ・文字列の場合:ロケールに応じた形式で parse
*
* 対応例:
* ・ja / ja_JP:yyyy/MM/dd HH:mm:ss
* ・en_US :MM/dd/yyyy HH:mm:ss
* ・en_GB :dd/MM/yyyy HH:mm:ss
*
* @param {*} value 画面入力値
* @returns {java.sql.Timestamp|null} SQL日時
* @throws {java.text.ParseException} 文字列 value がユーザーロケールの日時形式に一致しない場合、または不正な日時の場合
*/
function toSqlDateTime(value) {
if (value == null || value === '') {
return null;
}
var Timestamp = Java.type('java.sql.Timestamp');
if (value.getTime) {
return new Timestamp(value.getTime());
}
var pattern =
getDatePatternByLocale()
+ ' HH:mm:ss';
var utilDate = parseDate(value, pattern);
return new Timestamp(utilDate.getTime());
}
/**
* 値を java.util.Date に変換します。
*
* 対応型:
* ・String
* ・java.sql.Timestamp
* ・oracle.sql.TIMESTAMP
*
* @param {*} value
* @returns {*}
* @throws {java.text.ParseException} 文字型の value が判定された日付/日時形式に一致しない場合、または不正な日付の場合
*/
function toUtilDate(value) {
if (value == null || value === '') {
return value;
}
var type = Object.prototype.toString
.call(value)
.slice(8, -1)
.toUpperCase();
switch (type) {
case 'STRING':
return parseDate(
value,
getDatePatternByValue(value)
);
case 'JAVA.SQL.TIMESTAMP':
return new java.util.Date(
value.getTime()
);
case 'ORACLE.SQL.TIMESTAMP':
return new java.util.Date(
value.timestampValue().getTime()
);
default:
return value;
}
}
/**
* 文字列を指定フォーマットで
* java.util.Date に変換します。
*
* @param {*} value 画面入力値
* @param {string} pattern 日付フォーマット
* @returns {java.util.Date}
* @throws {java.text.ParseException} value が pattern に一致しない場合、または不正な日付の場合
*/
function parseDate(value, pattern) {
var SimpleDateFormat = Java.type(
'java.text.SimpleDateFormat'
);
var sdf = new SimpleDateFormat(pattern);
sdf.setLenient(false);
return sdf.parse(String(value));
}
/**
* 入力値に応じた
* 日付フォーマットを返します。
*
* @param {string} value
* @returns {string} 日付フォーマット
*/
function getDatePatternByValue(value) {
var pattern = getDatePatternByLocale();
if (String(value).indexOf(' ') >= 0) {
pattern += ' HH:mm:ss';
}
return pattern;
}
/**
* ログインユーザーの locale に応じた
* 日付フォーマットを返します。
*
* @returns {string} 日付フォーマット
*/
function getDatePatternByLocale() {
var userData = TALON.getUserInfoMap();
var locale = userData['LOCALE'];
if (!locale) {
return DEFAULT_DATE_PATTERN;
}
locale = String(locale).toLowerCase();
return DATE_PATTERN_BY_LOCALE[locale]
|| DEFAULT_DATE_PATTERN;
}
≣ サーバJS ライブラリTLN_AI_DEV_DEMO_INPUT_UTIL TLN_AI_DEV_DEMO_INPUT_UTIL 1137字
/**
* TLN_AI_DEV_DEMO_INPUT_UTIL
*
* 画面入力値の空判定・数値変換・チェックボックス値の配列変換を行うための共通関数です。
* JavaScriptエンジン APIマニュアル 11.3 入力値操作ユーティリティ の内容に沿っています。
*/
/**
* チェックボックス値の区切り文字です。
*
* TALON標準のチェックボックス区切り値(システム設定情報 CHECKBOX_SEP)に合わせて設定します。
*/
var CHECKBOX_VALUE_SEPARATOR = ';';
/**
* 空入力か判定します。
*
* @param {*} value 入力値
* @returns {boolean} 判定結果
*/
function isEmptyValue(value) {
return value === null
|| value === undefined
|| value === '';
}
/**
* 画面入力値を数値へ変換します。
* カンマ区切りが含まれる場合は、除去したうえで数値化します。
* ※ 数値変換できない場合は null 扱い(例: "abc", "12a")
*
* @param {*} value 画面入力値
* @returns {number|null} 数値。空入力の場合は null
*/
function toNumber(value) {
if (isEmptyValue(value)) {
return null;
}
var num = Number(
String(value).replace(/,/g, '')
);
if (isNaN(num)) {
return null;
}
return num;
}
/**
* チェックボックス値を配列へ変換します。
*
* @param {*} value チェックボックス値(区切り文字つきの文字列)
* @returns {Array<string>} チェック済み値配列
*/
function toCheckboxArray(value) {
if (isEmptyValue(value)) {
return [];
}
return String(value)
.split(CHECKBOX_VALUE_SEPARATOR);
}
≣ サーバJS ライブラリTLN_AI_DEV_DEMO_SQL_SET TLN_AI_DEV_DEMO_SQL_SET 2272字
/**
* TLN_AI_DEV_DEMO_SQL_SET
*
* UPDATE文のSET句を安全に組み立てるための共通関数です。
* JavaScriptエンジン APIマニュアル 11.5 SQLビルダ:SET句の組み立て(更新処理/NULL/SQL式対応) の内容に沿っています。
*/
/**
* SET句のコンテナを生成します。
*
* @returns {SetBuilder}
*
* @typedef {Object} SetBuilder
* @property {Array<Object>} items SET項目一覧
*/
function createSetBuilder() {
return {
items: []
};
}
/**
* SET(col = ?)を追加します。
*
* ・value が存在する場合:プレースホルダ「?」を使用して値を設定
* ・value が null / undefined の場合:
* - forceNull = true -> NULLを設定
* - forceNull = false -> 追加しない
* ・空文字や 0 は有効値として扱います
*
* @param {SetBuilder} setBuilder
* @param {string} column カラム名
* @param {*} value 設定値(null / undefined の場合は追加しない)
* @param {boolean} [forceNull=false] trueの場合、NULLを強制設定
* @returns {void}
*/
function addSet(setBuilder, column, value, forceNull) {
if (value === null || value === undefined) {
if (forceNull === true) {
setBuilder.items.push({
clause: column + ' = NULL',
values: []
});
}
return;
}
setBuilder.items.push({
clause: column + ' = ?',
values: [value]
});
}
/**
* 任意の式でSETを追加します(例:col = sysdate)
*
* @param {SetBuilder} setBuilder
* @param {*} condition 条件
* @param {string} expression SQL式
* @returns {void}
*/
function addSetRaw(setBuilder, condition, expression) {
if (!condition) {
return;
}
setBuilder.items.push({
clause: expression,
values: []
});
}
/**
* SET句を生成し、paramsに値を追加します。
*
* @param {SetBuilder} setBuilder
* @param {Array<*>} params バインドパラメータ
* @returns {string} SET句
* @throws {java.lang.IllegalArgumentException} UPDATE項目が指定されていない場合
*/
function buildSetSql(setBuilder, params) {
if (!setBuilder.items || setBuilder.items.length === 0) {
var IllegalArgumentException = Java.type('java.lang.IllegalArgumentException');
throw new IllegalArgumentException('No UPDATE items specified');
}
var parts = [];
for (var i = 0; i < setBuilder.items.length; i++) {
var item = setBuilder.items[i];
parts.push(item.clause);
for (var j = 0; j < item.values.length; j++) {
params.push(item.values[j]);
}
}
return ' SET ' + parts.join(', ');
}
≣ サーバJS ライブラリTLN_AI_DEV_DEMO_SQL_VALUES TLN_AI_DEV_DEMO_SQL_VALUES 2842字
/**
* TLN_AI_DEV_DEMO_SQL_VALUES
*
* INSERT文のカラム一覧とVALUES句を安全に組み立てるための共通関数です。
* JavaScriptエンジン APIマニュアル 11.6 SQLビルダ:VALUES句の組み立て(VALUES/NULL/SQL式対応) の内容に沿っています。
*/
/**
* INSERT文の組み立て用オブジェクトを作成します。
*
* @returns {InsertBuilder}
*
* @typedef {Object} InsertBuilder
* @property {Array<Object>} items INSERT項目一覧
*/
function createInsertBuilder() {
return {
items: []
};
}
/**
* INSERT項目を追加します。
*
* ・value が存在する場合:プレースホルダ「?」を使用して値を設定
* ・value が null / undefined の場合:
* - forceNull = true -> NULLを設定
* - forceNull = false -> 追加しない(カラムを除外)
* ・空文字や 0 は有効値として扱います
*
* @param {InsertBuilder} insertBuilder INSERTビルダ
* @param {string} column カラム名
* @param {*} value 登録値
* @param {boolean} [forceNull=false] trueの場合、NULLを強制設定
* @returns {void}
*/
function addInsertValue(insertBuilder, column, value, forceNull) {
if (value === null || value === undefined) {
if (forceNull === true) {
insertBuilder.items.push({
column: column,
placeholder: 'NULL',
values: []
});
}
return;
}
insertBuilder.items.push({
column: column,
placeholder: '?',
values: [value]
});
}
/**
* SQL式をINSERTします。
*
* 例:
* ・CURRENT_TIMESTAMP
* ・SYSDATE
* ・CURRENT_DATE
*
* @param {InsertBuilder} insertBuilder INSERTビルダ
* @param {*} condition 条件がtrueの場合に追加
* @param {string} column カラム名
* @param {string} expression SQL式
* @returns {void}
*/
function addInsertRaw(insertBuilder, condition, column, expression) {
if (!condition) {
return;
}
insertBuilder.items.push({
column: column,
placeholder: expression,
values: []
});
}
/**
* INSERT文を生成し、paramsに値を追加します。
*
* @param {string} tableName テーブル名
* @param {InsertBuilder} insertBuilder INSERTビルダ
* @param {Array<*>} params バインドパラメータ格納配列
* @returns {string} INSERT文
* @throws {java.lang.IllegalArgumentException} INSERT項目が指定されていない場合
*/
function buildInsertSql(tableName, insertBuilder, params) {
if (!insertBuilder.items || insertBuilder.items.length === 0) {
var IllegalArgumentException = Java.type('java.lang.IllegalArgumentException');
throw new IllegalArgumentException('No INSERT items specified');
}
var columns = [];
var placeholders = [];
for (var i = 0; i < insertBuilder.items.length; i++) {
var item = insertBuilder.items[i];
columns.push(item.column);
placeholders.push(item.placeholder);
for (var j = 0; j < item.values.length; j++) {
params.push(item.values[j]);
}
}
return ''
+ 'INSERT INTO ' + tableName + ' (\n'
+ ' ' + columns.join(',\n ') + '\n'
+ ') VALUES (\n'
+ ' ' + placeholders.join(',\n ') + '\n'
+ ')';
}
≣ サーバJS ライブラリTLN_AI_DEV_DEMO_SQL_WHERE TLN_AI_DEV_DEMO_SQL_WHERE 7362字
/**
* TLN_AI_DEV_DEMO_SQL_WHERE
*
* WHERE句を安全に組み立てるための共通関数です。
* JavaScriptエンジン APIマニュアル 11.4 SQLビルダ:WHERE条件の組み立て(AND / OR / LIKE / IN など) の内容に沿っています。
*
* 依存:
* - TLN_AI_DEV_DEMO_INPUT_UTIL(CHECKBOX_VALUE_SEPARATOR を参照)
* CHECKBOX_VALUE_SEPARATOR を参照するため、本JSを利用する機能は
* INPUT_UTIL も合わせて参照してください。
*/
/**
* WHERE句のグループ(論理ブロック)を生成します。
*
* @param {string} [operator='AND'] グループ内の論理演算子('AND' または 'OR')
* @returns {WhereGroup} WHEREグループオブジェクト
*
* @typedef {Object} WhereGroup
* @property {'group'} type ノード種別
* @property {string} operator 子要素を結合する論理演算子
* @property {Array<WhereNode>} children 子ノード一覧
*/
function createWhereGroup(operator) {
return {
type: 'group',
operator: operator || 'AND',
children: []
};
}
/**
* 通常の比較条件(=など)を追加します。
*
* @param {WhereGroup} group 追加先のWHEREグループ
* @param {string} clause SQL条件句(例: 'col = ?')
* @param {*} value バインド値(null / undefined の場合は追加しない)
* @returns {void}
*/
function addCondition(group, clause, value) {
if (value === null || value === undefined) {
return;
}
group.children.push({
type: 'condition',
clause: clause,
values: [value]
});
}
/**
* 通常の比較条件(=など)を追加します。
* condition が true の場合のみ条件を追加します。
*
* @param {WhereGroup} group 追加先のWHEREグループ
* @param {boolean} condition 条件追加判定(false の場合は追加しない)
* @param {string} clause SQL条件句(例: 'col = ?')
* @param {*} value バインド値
* @returns {void}
*/
function addConditionIf(group, condition, clause, value) {
if (condition !== true) {
return;
}
addCondition(group, clause, value);
}
/**
* LIKE条件を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {*} value 検索値(null / undefined / 空文字は無視)
* @param {string} column カラム名
* @param {'contains'|'prefix'|'suffix'|'exact'} [matchType='contains'] 一致方式
* @returns {void}
*/
function addLikeCondition(group, value, column, matchType) {
if (value === null || value === undefined || value === '') {
return;
}
var likeValue;
switch (matchType || 'contains') {
case 'prefix':
likeValue = value + '%';
break;
case 'suffix':
likeValue = '%' + value;
break;
case 'exact':
likeValue = value;
break;
case 'contains':
default:
likeValue = '%' + value + '%';
break;
}
group.children.push({
type: 'condition',
clause: column + ' LIKE ?',
values: [likeValue]
});
}
/**
* IN条件を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {Array<*>} values 検索値配列(空配列の場合は追加しない)
* @param {string} column カラム名
* @returns {void}
*/
function addInCondition(group, values, column) {
if (!values || values.length === 0) {
return;
}
var placeholders = [];
for (var i = 0; i < values.length; i++) {
placeholders.push('?');
}
group.children.push({
type: 'condition',
clause: column + ' IN (' + placeholders.join(', ') + ')',
values: values
});
}
/**
* BETWEEN条件を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {*} from 開始値
* @param {*} to 終了値
* @param {string} column カラム名
* @returns {void}
*/
function addBetweenCondition(group, from, to, column) {
if (from === null || from === undefined ||
to === null || to === undefined) {
return;
}
group.children.push({
type: 'condition',
clause: column + ' BETWEEN ? AND ?',
values: [from, to]
});
}
/**
* IS NULL 条件を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {*} condition 条件追加判定(true の場合に追加)
* @param {string} column カラム名
* @returns {void}
*/
function addIsNullCondition(group, condition, column) {
if (!condition) {
return;
}
group.children.push({
type: 'condition',
clause: column + ' IS NULL',
values: []
});
}
/**
* IS NOT NULL 条件を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {*} condition 条件追加判定(true の場合に追加)
* @param {string} column カラム名
* @returns {void}
*/
function addIsNotNullCondition(group, condition, column) {
if (!condition) {
return;
}
group.children.push({
type: 'condition',
clause: column + ' IS NOT NULL',
values: []
});
}
/**
* チェックボックス値検索用のLIKEパターンを生成します。
*
* @param {*} value チェックボックス値
* @returns {string} LIKE検索用パターン
*/
function toCheckboxLikePattern(value) {
return '%'
+ CHECKBOX_VALUE_SEPARATOR
+ String(value)
+ CHECKBOX_VALUE_SEPARATOR
+ '%';
}
/**
* DBカラムの区切り文字で保持されたチェックボックス値に対して、
* 「いずれかを含む」検索条件(OR条件)を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {Array<*>} values 検索値配列
* @param {string} column カラム名
* @returns {void}
*/
function addCheckboxCondition(group, values, column) {
if (!values || values.length === 0) {
return;
}
var orGroup = addGroup(group, 'OR');
for (var i = 0; i < values.length; i++) {
addCondition(
orGroup,
"CONCAT('"
+ CHECKBOX_VALUE_SEPARATOR
+ "', CONCAT("
+ column
+ ", '"
+ CHECKBOX_VALUE_SEPARATOR
+ "')) LIKE ? escape '$'",
toCheckboxLikePattern(values[i])
);
}
}
/**
* DBカラムの区切り文字で保持されたチェックボックス値に対して、
* 「すべて含まない」検索条件(AND条件)を追加します。
*
* @param {WhereGroup} group WHEREグループ
* @param {Array<*>} values 検索値配列
* @param {string} column カラム名
* @returns {void}
*/
function addNotCheckboxCondition(group, values, column) {
if (!values || values.length === 0) {
return;
}
var andGroup = addGroup(group, 'AND');
for (var i = 0; i < values.length; i++) {
addCondition(
andGroup,
"CONCAT('"
+ CHECKBOX_VALUE_SEPARATOR
+ "', CONCAT("
+ column
+ ", '"
+ CHECKBOX_VALUE_SEPARATOR
+ "')) NOT LIKE ? escape '$'",
toCheckboxLikePattern(values[i])
);
}
}
/**
* 子グループ(括弧)を追加します。
*
* @param {WhereGroup} parentGroup 親グループ
* @param {string} [operator='AND'] 子グループ内の論理演算子
* @returns {WhereGroup} 生成された子グループ
*/
function addGroup(parentGroup, operator) {
var group = createWhereGroup(operator);
parentGroup.children.push(group);
return group;
}
/**
* WHERE句のSQL文字列を生成し、params配列にバインド値を追加します。
*
* ・再帰的にグループを展開
* ・condition はそのままSQLに追加
* ・group は括弧で囲む
* ・values は params に順序通り追加
*
* @param {WhereGroup} group WHEREグループ
* @param {Array<*>} params バインドパラメータ格納配列(副作用で追加される)
* @returns {string} WHERE句(条件部分のみ)
*/
function buildWhereSql(group, params) {
if (!group.children || group.children.length === 0) {
return '';
}
var parts = [];
for (var i = 0; i < group.children.length; i++) {
var child = group.children[i];
if (child.type === 'condition') {
parts.push(child.clause);
for (var j = 0; j < child.values.length; j++) {
params.push(child.values[j]);
}
} else if (child.type === 'group') {
var groupSql = buildWhereSql(child, params);
if (groupSql) {
parts.push('(' + groupSql + ')');
}
}
}
return parts.join(' ' + group.operator + ' ');
}
≣ サーバJS ライブラリTLN_ANALYZE_COMMON 共通JavaScript_リポジトリ分析共通部品 42080字
/**
* TLN_ANALYZE_COMMON : 共通JavaScript_リポジトリ分析共通部品
*
* 最終更新: TALON_ANALYZE_V2_0_1
* @version 2024/03/25
*/
//----------------------------------------------
function tln_com_datetime2string(obj) {
return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + " " + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
}
function tln_com_zpad2(str) {
return ( '0' + str ).slice( -2 );
}
function tln_com_nowdate() {
var sysDate = new java.util.Date();
return sysDate;
}
function tln_com_escape(val) {
var toStr = Object.prototype.toString;
var tType = toStr.call( val ).slice(8, -1).toUpperCase();
if (tType == 'STRING' ) {
return val.replace( /'/g , "''" );
} else {
return val;
}
}
function tln_com_func_id() {
var lineDataMap = TALON.getUserInfoMap();
var _FUNC_ID = getMapVal( lineDataMap , 'FUNC_ID' );
return _FUNC_ID;
}
function tln_com_user_id() {
var lineDataMap = TALON.getUserInfoMap();
var _USER_ID = getMapVal( lineDataMap , 'USER_ID' );
return _USER_ID;
}
//-------------------------------------------
function tln_insertByMap(tbl, lst ,name) {
if ( chkLowercase() ) {
TalonDbUtil.insertByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name );
} else {
TalonDbUtil.insertByMap( TALON.getDbConfig(), tbl , lst , name );
}
}
function tln_updateByMap(tbl, lst ,name ,where) {
if ( chkLowercase() ) {
TalonDbUtil.updateByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name , where);
} else {
TalonDbUtil.updateByMap( TALON.getDbConfig(), tbl , lst , name , where);
}
}
function tln_deleteByMap(tbl, lst ,name) {
if ( chkLowercase() ) {
TalonDbUtil.deleteByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name );
} else {
TalonDbUtil.deleteByMap( TALON.getDbConfig(), tbl , lst , name );
}
}
//-------------------------------------------
function getMapVal(map , id) {
var _rec = null;
_rec = map[id];
if (_rec == null) {
_rec = map[id.toLowerCase()];
}
return _rec;
}
function setMapVal(map , id , val) {
if ( TALON.getDbConfig().isPostgres() ) {
map[ id.toLowerCase() ] = val;
} else {
map[ id ] = val;
}
}
function getBindVal(key) {
var _rec = null;
if ( TALON.getDbConfig().isPostgres() ) {
_rec = TALON.getBindValue( key.toLowerCase() );
} else {
_rec = TALON.getBindValue( key );
}
return _rec;
}
function removeBindVal(key) {
if ( TALON.getDbConfig().isPostgres() ) {
TALON.removeBindValue( key.toLowerCase() );
} else {
TALON.removeBindValue( key );
}
}
function putBindVal(key , val) {
if ( TALON.getDbConfig().isPostgres() ) {
TALON.putBindValue( key.toLowerCase() , val );
} else {
TALON.putBindValue( key , val );
}
}
function chkLowercase() {
if ( TALON.getDbConfig().isPostgres() ) {
return true;
} else if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE BINARY TABLE_NAME = BINARY 'TLN_ANALYZE_INFO' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal( lineDataMap , 'CNT' );
if (_CNT == 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
function editLowList(obj) {
if ( TALON.getDbConfig().isPostgres() ) {
for(var lop = 0; lop < obj.length; lop++) {
obj[lop] = obj[lop].toLowerCase();
}
}
return obj;
}
// * function tln_getSysdate() {
// * var sql = "SELECT TLN_SYSDATE() AS NOWDATE FROM TLN_M_HANYO_CODE_MAIN " +
// * "WHERE SIKIBETU_CODE LIKE 'TLN_ANALYZE_ONE' ";
// * var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
// * var lineDataMap = itemSelectList[0];
// * var _NOWDATE = getMapVal( lineDataMap , 'NOWDATE' );
// * return _NOWDATE;
// * }
function tln_get_sysdate_created_date() {
var obj = tln_com_nowdate();
// * if ( TALON.getDbConfig().isPostgres() ) {
// * return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + "T" + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
// * } else {
// * return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + " " + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
// * }
// * return (obj.getYear()+1900) + "/" + tln_com_zpad2(obj.getMonth()+1) + "/" + tln_com_zpad2(obj.getDate()) + " " + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
return new java.util.Date();
}
//----------------------------------------------
var itemColNameTbl_TLN_ANALYZE_INFO = [
'FUNC_ID'
, 'FUNC_SEQ'
, 'FUNC_KBN'
, 'COL_NAME'
, 'OPT_SORT'
, 'EVENT_TYPE'
, 'DATA_TYPE'
, 'MOCK_SEQ'
, 'SEQ'
, 'CHR_TEXT1'
, 'CHR_TEXT2'
, 'CREATED_DATE'
, 'CREATED_BY'
, 'CREATED_PRG_NM'
, 'UPDATED_DATE'
, 'UPDATED_BY'
, 'UPDATED_PRG_NM'
];
itemColNameTbl_TLN_ANALYZE_INFO = editLowList(itemColNameTbl_TLN_ANALYZE_INFO);
//----------------------------------------------
var tableName_TLN_ANALYZE_INFO = 'TLN_ANALYZE_INFO';
if ( chkLowercase() ) {
tableName_TLN_ANALYZE_INFO = tableName_TLN_ANALYZE_INFO.toLowerCase()
}
//----------------------------------------------
var tableName_TLN_ANALYZE_INFO_LOG = 'TLN_ANALYZE_INFO_LOG';
if ( chkLowercase() ) {
tableName_TLN_ANALYZE_INFO_LOG = tableName_TLN_ANALYZE_INFO_LOG.toLowerCase()
}
//----------------------------------------------
function _tln_create_analyze_info( itemDataList ) {
TalonDbUtil.insertByMap( TALON.getDbConfig() , tableName_TLN_ANALYZE_INFO, itemDataList , itemColNameTbl_TLN_ANALYZE_INFO );
}
function _tln_update_analyze_info( itemDataList , whereList ) {
var iCount = TalonDbUtil.updateByMap( TALON.getDbConfig() , tableName_TLN_ANALYZE_INFO, itemDataList, itemColNameTbl_TLN_ANALYZE_INFO, whereList );
}
function _tln_delete_analyze_info( itemDataList , whereList) {
var iCount = TalonDbUtil.deleteByMap( TALON.getDbConfig(), tableName_TLN_ANALYZE_INFO, itemDataList, whereList );
}
//----------------------------------------------
function _tln_create_analyze_info_autocommit( itemDataList ) {
TalonDbUtil.insertByMap( TALON.getSubDBConn() , tableName_TLN_ANALYZE_INFO_LOG, itemDataList , itemColNameTbl_TLN_ANALYZE_INFO );
TalonDbUtil.commit( TALON.getSubDBConn() );
}
function _tln_update_analyze_info_autocommit( itemDataList , whereList ) {
var iCount = TalonDbUtil.updateByMap( TALON.getSubDBConn() , tableName_TLN_ANALYZE_INFO_LOG, itemDataList, itemColNameTbl_TLN_ANALYZE_INFO, whereList );
TalonDbUtil.commit( TALON.getSubDBConn() );
}
function _tln_delete_analyze_info_autocommit( itemDataList , whereList) {
var iCount = TalonDbUtil.deleteByMap( TALON.getSubDBConn(), tableName_TLN_ANALYZE_INFO_LOG, itemDataList, whereList );
TalonDbUtil.commit( TALON.getSubDBConn() );
}
//----------------------------------------------
var _tln_analyze_mock_no = 0;
function _tln_analyze_set_mock_no(val) {
_tln_analyze_mock_no = val;
}
//----------------------------------------------
var _g_FUNC_ID = '';
var _g_FUNC_SEQ = '';
var _g_FUNC_KBN = '';
var _g_COL_NAME = '';
var _g_OPT_SORT = '';
var _tln_analyze_log = '';
function _tln_analyze_exec_mode() {
var _FUNC_ID = tln_com_func_id();
if ( _FUNC_ID == 'TLN_ANALYZE_TEST01' || _FUNC_ID == 'TLN_ANALYZE_TEST02' || _FUNC_ID == 'TLN_ANALYZE_TEST15' ) {
return 'DEBUG';
} else {
return '';
}
}
function _tln_analyze_js_init(_FUNC_ID, _FUNC_SEQ, _COL_NAME, _FUNC_KBN, _OPT_SORT) {
var _my_USER_ID = tln_com_user_id();
var _my_FUNC_ID = tln_com_func_id();
var _SYSDATE = tln_get_sysdate_created_date(); //tln_com_datetime2string( tln_com_nowdate() );
_g_FUNC_ID = _FUNC_ID;
_g_FUNC_SEQ = _FUNC_SEQ;
_g_FUNC_KBN = _FUNC_KBN;
_g_COL_NAME = _COL_NAME;
_g_OPT_SORT = _OPT_SORT;
//変数の初期化
_tln_analyze_log = '';
//EXECUTE用のコネクションを作成(autocommit)
TALON.createSubDBConfig();
var itemDataList_EXECUTE = new Array();
setMapVal( itemDataList_EXECUTE , 'FUNC_ID' , _g_FUNC_ID );
setMapVal( itemDataList_EXECUTE , 'FUNC_SEQ' , _g_FUNC_SEQ );
setMapVal( itemDataList_EXECUTE , 'FUNC_KBN' , _g_FUNC_KBN );
setMapVal( itemDataList_EXECUTE , 'COL_NAME' , _g_COL_NAME );
setMapVal( itemDataList_EXECUTE , 'OPT_SORT' , _g_OPT_SORT );
setMapVal( itemDataList_EXECUTE , 'EVENT_TYPE' , 'EXECUTE' );
setMapVal( itemDataList_EXECUTE , 'DATA_TYPE' , 'ENGINE' );
setMapVal( itemDataList_EXECUTE , 'SEQ' , 0 );
var whereList_EXECUTE = new Array();
if ( TALON.getDbConfig().isPostgres() ) {
whereList_EXECUTE.push( [ null, '=' , 'func_id' ] );
whereList_EXECUTE.push( [ null, '=' , 'func_seq' ] );
whereList_EXECUTE.push( [ null, '=' , 'func_kbn' ] );
whereList_EXECUTE.push( [ null, '=' , 'col_name' ] );
whereList_EXECUTE.push( [ null, '=' , 'opt_sort' ] );
whereList_EXECUTE.push( [ null, '=' , 'event_type' ] );
whereList_EXECUTE.push( [ null, '=' , 'data_type' ] );
whereList_EXECUTE.push( [ null, '=' , 'mock_seq' ] );
whereList_EXECUTE.push( [ null, '=' , 'seq' ] );
} else {
whereList_EXECUTE.push( [ null, '=' , 'FUNC_ID' ] );
whereList_EXECUTE.push( [ null, '=' , 'FUNC_SEQ' ] );
whereList_EXECUTE.push( [ null, '=' , 'FUNC_KBN' ] );
whereList_EXECUTE.push( [ null, '=' , 'COL_NAME' ] );
whereList_EXECUTE.push( [ null, '=' , 'OPT_SORT' ] );
whereList_EXECUTE.push( [ null, '=' , 'EVENT_TYPE' ] );
whereList_EXECUTE.push( [ null, '=' , 'DATA_TYPE' ] );
whereList_EXECUTE.push( [ null, '=' , 'MOCK_SEQ' ] );
whereList_EXECUTE.push( [ null, '=' , 'SEQ' ] );
}
//モック番号が0以外の場合、既に登録されているモック番号0のデータ(モックが作られていなかった時のログ)は削除する
setMapVal( itemDataList_EXECUTE, 'MOCK_SEQ' , 0 );
_tln_delete_analyze_info_autocommit( itemDataList_EXECUTE , whereList_EXECUTE );
//EXECUTEデータの削除
setMapVal( itemDataList_EXECUTE, 'MOCK_SEQ' , _tln_analyze_mock_no );
_tln_delete_analyze_info_autocommit( itemDataList_EXECUTE , whereList_EXECUTE );
setMapVal( itemDataList_EXECUTE , 'CHR_TEXT1' , '※ERROR※' ); //初期時にERRORとして更新し、正常終了時にクリアを行う
setMapVal( itemDataList_EXECUTE , 'CREATED_DATE' , _SYSDATE );
setMapVal( itemDataList_EXECUTE , 'CREATED_BY' , _my_USER_ID );
setMapVal( itemDataList_EXECUTE , 'CREATED_PRG_NM' , _my_FUNC_ID );
setMapVal( itemDataList_EXECUTE , 'UPDATED_DATE' , _SYSDATE );
setMapVal( itemDataList_EXECUTE , 'UPDATED_BY' , _my_USER_ID );
setMapVal( itemDataList_EXECUTE , 'UPDATED_PRG_NM' , _my_FUNC_ID );
//EXECUTEデータの作成
_tln_create_analyze_info_autocommit(itemDataList_EXECUTE);
var itemDataList = new Array();
setMapVal( itemDataList , 'FUNC_ID' , _g_FUNC_ID );
setMapVal( itemDataList , 'FUNC_SEQ' , _g_FUNC_SEQ );
setMapVal( itemDataList , 'FUNC_KBN' , _g_FUNC_KBN );
setMapVal( itemDataList , 'COL_NAME' , _g_COL_NAME );
setMapVal( itemDataList , 'OPT_SORT' , _g_OPT_SORT );
setMapVal( itemDataList , 'DATA_TYPE' , 'ENGINE' );
setMapVal( itemDataList , 'MOCK_SEQ' , _tln_analyze_mock_no );
var whereList = new Array();
if ( TALON.getDbConfig().isPostgres() ) {
whereList.push( [ null, '=' , 'func_id' ] );
whereList.push( [ null, '=' , 'func_seq' ] );
whereList.push( [ null, '=' , 'func_kbn' ] );
whereList.push( [ null, '=' , 'col_name' ] );
whereList.push( [ null, '=' , 'opt_sort' ] );
whereList.push( [ null, '=' , 'data_type' ] );
whereList.push( [ null, '=' , 'mock_seq' ] );
} else {
whereList.push( [ null, '=' , 'FUNC_ID' ] );
whereList.push( [ null, '=' , 'FUNC_SEQ' ] );
whereList.push( [ null, '=' , 'FUNC_KBN' ] );
whereList.push( [ null, '=' , 'COL_NAME' ] );
whereList.push( [ null, '=' , 'OPT_SORT' ] );
whereList.push( [ null, '=' , 'DATA_TYPE' ] );
whereList.push( [ null, '=' , 'MOCK_SEQ' ] );
}
//データの初期化
_tln_delete_analyze_info( itemDataList , whereList )
/*
var sql = "DELETE FROM TLN_ANALYZE_INFO " +
"WHERE FUNC_ID = '" + tln_com_escape(_g_FUNC_ID) + "' " +
" AND FUNC_SEQ = " + _g_FUNC_SEQ + " " +
" AND FUNC_KBN = '" + tln_com_escape(_g_FUNC_KBN) + "' " +
" AND COL_NAME = '" + tln_com_escape(_g_COL_NAME) + "' " +
" AND OPT_SORT = " + _g_OPT_SORT + " " +
" AND DATA_TYPE = '" + 'ENGINE' + "' " +
" AND MOCK_SEQ = " + _tln_analyze_mock_no + " " +
" AND EVENT_TYPE <> '" + 'EXECUTE' + "' " +
"";
var iCount = TalonDbUtil.delete( TALON.getDbConfig() , sql );
*/
}
function _tln_analyze_js_end() {
var _my_USER_ID = tln_com_user_id();
var _my_FUNC_ID = tln_com_func_id();
var _SYSDATE = tln_get_sysdate_created_date(); //tln_com_datetime2string( tln_com_nowdate() );
var itemDataList_EXECUTE = new Array();
setMapVal( itemDataList_EXECUTE , 'FUNC_ID' , _g_FUNC_ID );
setMapVal( itemDataList_EXECUTE , 'FUNC_SEQ' , _g_FUNC_SEQ );
setMapVal( itemDataList_EXECUTE , 'FUNC_KBN' , _g_FUNC_KBN );
setMapVal( itemDataList_EXECUTE , 'COL_NAME' , _g_COL_NAME );
setMapVal( itemDataList_EXECUTE , 'OPT_SORT' , _g_OPT_SORT );
setMapVal( itemDataList_EXECUTE , 'EVENT_TYPE' , 'EXECUTE' );
setMapVal( itemDataList_EXECUTE , 'DATA_TYPE' , 'ENGINE' );
setMapVal( itemDataList_EXECUTE , 'MOCK_SEQ' , _tln_analyze_mock_no );
setMapVal( itemDataList_EXECUTE , 'SEQ' , 0 );
setMapVal( itemDataList_EXECUTE , 'CHR_TEXT1' , '' );
var whereList_EXECUTE = new Array();
if ( TALON.getDbConfig().isPostgres() ) {
whereList_EXECUTE.push( [ null, '=' , 'func_id' ] );
whereList_EXECUTE.push( [ null, '=' , 'func_seq' ] );
whereList_EXECUTE.push( [ null, '=' , 'func_kbn' ] );
whereList_EXECUTE.push( [ null, '=' , 'col_name' ] );
whereList_EXECUTE.push( [ null, '=' , 'opt_sort' ] );
whereList_EXECUTE.push( [ null, '=' , 'event_type' ] );
whereList_EXECUTE.push( [ null, '=' , 'data_type' ] );
whereList_EXECUTE.push( [ null, '=' , 'mock_seq' ] );
whereList_EXECUTE.push( [ null, '=' , 'seq' ] );
} else {
whereList_EXECUTE.push( [ null, '=' , 'FUNC_ID' ] );
whereList_EXECUTE.push( [ null, '=' , 'FUNC_SEQ' ] );
whereList_EXECUTE.push( [ null, '=' , 'FUNC_KBN' ] );
whereList_EXECUTE.push( [ null, '=' , 'COL_NAME' ] );
whereList_EXECUTE.push( [ null, '=' , 'OPT_SORT' ] );
whereList_EXECUTE.push( [ null, '=' , 'EVENT_TYPE' ] );
whereList_EXECUTE.push( [ null, '=' , 'DATA_TYPE' ] );
whereList_EXECUTE.push( [ null, '=' , 'MOCK_SEQ' ] );
whereList_EXECUTE.push( [ null, '=' , 'SEQ' ] );
}
//EXECUTEデータの初期化
_tln_update_analyze_info_autocommit( itemDataList_EXECUTE , whereList_EXECUTE )
}
function _tln_analyze_set_data(_DATA_TYPE , _NAME , _EVENT_TYPE) {
_tln_analyze_set_data_main(_DATA_TYPE , _NAME , '' , _EVENT_TYPE)
}
function _tln_analyze_set_data_item(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE) {
_tln_analyze_set_data_main(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE)
}
function _tln_analyze_set_data_main(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE) {
if (_NAME != '' ) {
//TABLE名を分割して登録する(_NAME)
var _NAME_ARRAY = _NAME.split(';');
for (var iTable = 0; iTable < _NAME_ARRAY.length; iTable++) {
_NAME = _NAME_ARRAY[iTable];
var _ITEM_ARRAY = _ITEM.split(';');
if (_ITEM_ARRAY.length > 0) {
for (var iItem = 0; iItem < _ITEM_ARRAY.length; iItem++) {
_ITEM = _ITEM_ARRAY[iItem];
_tln_analyze_set_data_exec(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE);
}
} else {
_tln_analyze_set_data_exec(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE);
}
}
} else {
var _ITEM_ARRAY = _ITEM.split(';');
if (_ITEM_ARRAY.length > 0) {
for (var iItem = 0; iItem < _ITEM_ARRAY.length; iItem++) {
_ITEM = _ITEM_ARRAY[iItem];
_tln_analyze_set_data_exec(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE);
}
} else {
//TABLE も ITEM も空の場合
//_tln_analyze_set_data_exec(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE);
}
}
}
function _tln_analyze_set_data_exec(_DATA_TYPE , _NAME , _ITEM , _EVENT_TYPE) {
var _my_USER_ID = tln_com_user_id();
var _my_FUNC_ID = tln_com_func_id();
var _SYSDATE = tln_get_sysdate_created_date(); //tln_com_datetime2string( tln_com_nowdate() );
//DB毎にCREATE文作成時に付与される囲い文字列を置換
var _NAME = _NAME.replace( /`/g , '' );
//同じテーブル名と項目名が有る場合は更新しない
var sql = "SELECT COUNT(*) AS CNT FROM TLN_ANALYZE_INFO " +
"WHERE FUNC_ID = '" + tln_com_escape(_g_FUNC_ID ) + "' " +
" AND FUNC_SEQ = " + tln_com_escape(_g_FUNC_SEQ) + " " +
" AND FUNC_KBN = '" + tln_com_escape(_g_FUNC_KBN) + "' " +
" AND COL_NAME = '" + tln_com_escape(_g_COL_NAME) + "' " +
" AND OPT_SORT = " + tln_com_escape(_g_OPT_SORT) + " " +
" AND EVENT_TYPE = '" + tln_com_escape(_EVENT_TYPE) + "' " +
" AND DATA_TYPE = '" + tln_com_escape(_DATA_TYPE ) + "' " +
" AND MOCK_SEQ = " + _tln_analyze_mock_no + " ";
if ( TALON.getDbConfig().isOra() ) {
if ( (_NAME == '') || (_NAME == null) ) {
sql = sql + " AND TLN_ANALYZE_CONV_CHAR( CHR_TEXT1 ) is null ";
} else {
sql = sql + " AND TLN_ANALYZE_CONV_CHAR( CHR_TEXT1 ) = '" + tln_com_escape(_NAME) + "' ";
}
if ( (_ITEM == '') || (_ITEM == null) ) {
sql = sql + " AND TLN_ANALYZE_CONV_CHAR( CHR_TEXT2 ) is null ";
} else {
sql = sql + " AND TLN_ANALYZE_CONV_CHAR( CHR_TEXT2 ) = '" + tln_com_escape(_ITEM) + "' ";
}
} else {
sql = sql + " AND CHR_TEXT1 = '" + tln_com_escape(_NAME) + "' ";
sql = sql + " AND CHR_TEXT2 = '" + tln_com_escape(_ITEM) + "' ";
}
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal( lineDataMap , 'CNT' );
if ( _CNT == 0 ) {
var _MODE = 'I';
} else {
//既に存在するので何もしない
var _MODE = 'X';
}
//-------------------
var sql = "SELECT CASE WHEN MAX(SEQ) IS NULL THEN 0 ELSE MAX(SEQ) END + 1 AS MAX_SEQ , COUNT(*) AS CNT FROM TLN_ANALYZE_INFO " +
"WHERE FUNC_ID = '" + tln_com_escape(_g_FUNC_ID ) + "' " +
" AND FUNC_SEQ = " + tln_com_escape(_g_FUNC_SEQ) + " " +
" AND COL_NAME = '" + tln_com_escape(_g_COL_NAME) + "' " +
" AND FUNC_KBN = '" + tln_com_escape(_g_FUNC_KBN) + "' " +
" AND OPT_SORT = " + tln_com_escape(_g_OPT_SORT) + " " +
" AND EVENT_TYPE = '" + tln_com_escape(_EVENT_TYPE) + "' " +
" AND DATA_TYPE = '" + tln_com_escape(_DATA_TYPE ) + "' " +
" AND MOCK_SEQ = '" + _tln_analyze_mock_no + "' ";
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
var lineDataMap = itemSelectList[0];
var _SEQ = getMapVal( lineDataMap , 'MAX_SEQ' );
//-------------------
var itemDataList = new Array();
setMapVal( itemDataList , 'FUNC_ID' , _g_FUNC_ID );
setMapVal( itemDataList , 'FUNC_SEQ' , _g_FUNC_SEQ );
setMapVal( itemDataList , 'FUNC_KBN' , _g_FUNC_KBN );
setMapVal( itemDataList , 'COL_NAME' , _g_COL_NAME );
setMapVal( itemDataList , 'OPT_SORT' , _g_OPT_SORT );
setMapVal( itemDataList , 'EVENT_TYPE' , _EVENT_TYPE );
setMapVal( itemDataList , 'DATA_TYPE' , _DATA_TYPE );
setMapVal( itemDataList , 'MOCK_SEQ' , _tln_analyze_mock_no );
setMapVal( itemDataList , 'SEQ' , _SEQ );
setMapVal( itemDataList , 'CHR_TEXT1' , _NAME );
setMapVal( itemDataList , 'CHR_TEXT2' , _ITEM );
setMapVal( itemDataList , 'UPDATED_DATE' , _SYSDATE );
setMapVal( itemDataList , 'UPDATED_BY' , _my_USER_ID );
setMapVal( itemDataList , 'UPDATED_PRG_NM' , _my_FUNC_ID );
if (_MODE == 'I' ) {
setMapVal( itemDataList , 'CREATED_DATE' , _SYSDATE );
setMapVal( itemDataList , 'CREATED_BY' , _my_USER_ID );
setMapVal( itemDataList , 'CREATED_PRG_NM' , _my_FUNC_ID );
_tln_create_analyze_info(itemDataList);
}
if (_MODE == 'U' ) {
var whereList = new Array();
if ( TALON.getDbConfig().isPostgres() ) {
whereList.push( [ null, '=' , 'func_id' ] );
whereList.push( [ null, '=' , 'func_seq' ] );
whereList.push( [ null, '=' , 'func_kbn' ] );
whereList.push( [ null, '=' , 'col_name' ] );
whereList.push( [ null, '=' , 'opt_sort' ] );
whereList.push( [ null, '=' , 'event_type' ] );
whereList.push( [ null, '=' , 'data_type' ] );
whereList.push( [ null, '=' , 'mock_seq' ] );
whereList.push( [ null, '=' , 'seq' ] );
} else {
whereList.push( [ null, '=' , 'FUNC_ID' ] );
whereList.push( [ null, '=' , 'FUNC_SEQ' ] );
whereList.push( [ null, '=' , 'FUNC_KBN' ] );
whereList.push( [ null, '=' , 'COL_NAME' ] );
whereList.push( [ null, '=' , 'OPT_SORT' ] );
whereList.push( [ null, '=' , 'EVENT_TYPE' ] );
whereList.push( [ null, '=' , 'DATA_TYPE' ] );
whereList.push( [ null, '=' , 'MOCK_SEQ' ] );
whereList.push( [ null, '=' , 'SEQ' ] );
}
_tln_update_analyze_info( itemDataList , whereList )
}
}
//----------------------------------------------
var _tln_analyze_mock = null;
function _tln_analyze_mock_data( mock ) {
eval( "_tln_analyze_mock = " + mock ) ;
}
//----------------------------------------------
function _tln_analyze_select_table_name(_SQL) {
if (_SQL.length > 0) {
var _CHECK = 0;
var _IDX = 0;
var _SQL_TABLE = new Array();
var _SQL_ARRAY = _SQL.replace( /\t/g , ' ' ).replace( /\r?\n/g , ' ' ).split(' ');
for (var iName = 0; iName < _SQL_ARRAY.length; iName++) {
if (_SQL_ARRAY[iName] != '' ) {
if (_CHECK == 1) {
if (_SQL_ARRAY[iName].substring(0, 1) != '(') {
_SQL_TABLE[_IDX] = _SQL_ARRAY[iName];
_IDX++
}
_CHECK = 0;
}
if (_SQL_ARRAY[iName].toUpperCase() == 'FROM' ) {
_CHECK = 1;
}
if (_SQL_ARRAY[iName].toUpperCase() == 'JOIN' ) {
_CHECK = 1;
}
}
}
return _SQL_TABLE.join(";");
} else {
return "";
}
}
function _tln_analyze_insert_table_name(_SQL) {
if (_SQL.length > 0) {
var _CHECK = 0;
var _IDX = 0;
var _SQL_TABLE = new Array();
var _SQL_ARRAY = _SQL.replace( /\t/g , ' ' ).replace( /\r?\n/g , ' ' ).split(' ');
for (var iName = 0; iName < _SQL_ARRAY.length; iName++) {
if (_SQL_ARRAY[iName] != '' ) {
if (_CHECK == 2) {
_SQL_TABLE[_IDX] = _SQL_ARRAY[iName];
_IDX++
_CHECK = 0;
}
if (_CHECK == 1 ) {
if (_SQL_ARRAY[iName].toUpperCase() == 'INTO' ) {
_CHECK = 2;
} else {
//INSERT の次が INTOでない場合はリセット
_CHECK = 0;
}
}
if (_SQL_ARRAY[iName].toUpperCase() == 'INSERT' ) {
_CHECK = 1;
}
}
}
return _SQL_TABLE.join(";");
} else {
return "";
}
}
function _tln_analyze_update_table_name(_SQL) {
if (_SQL.length > 0) {
var _CHECK = 0;
var _IDX = 0;
var _SQL_TABLE = new Array();
var _SQL_ARRAY = _SQL.replace( /\t/g , ' ' ).replace( /\r?\n/g , ' ' ).split(' ');
for (var iName = 0; iName < _SQL_ARRAY.length; iName++) {
if (_SQL_ARRAY[iName] != '' ) {
if (_CHECK == 1) {
_SQL_TABLE[_IDX] = _SQL_ARRAY[iName];
_IDX++
_CHECK = 0;
}
if (_SQL_ARRAY[iName].toUpperCase() == 'UPDATE' ) {
_CHECK = 1;
}
}
}
return _SQL_TABLE.join(";");
} else {
return "";
}
}
function _tln_analyze_delete_table_name(_SQL) {
if (_SQL.length > 0) {
var _CHECK = 0;
var _IDX = 0;
var _SQL_TABLE = new Array();
var _SQL_ARRAY = _SQL.replace( /\t/g , ' ' ).replace( /\r?\n/g , ' ' ).split(' ');
for (var iName = 0; iName < _SQL_ARRAY.length; iName++) {
if (_SQL_ARRAY[iName] != '' ) {
if (_CHECK == 1) {
_SQL_TABLE[_IDX] = _SQL_ARRAY[iName];
_IDX++
_CHECK = 0;
}
if (_SQL_ARRAY[iName].toUpperCase() == 'FROM' ) {
_CHECK = 1;
}
}
}
return _SQL_TABLE.join(";");
} else {
return "";
}
}
function _tln_analyze_dataMap_item_name(lineDataMap) {
var rec = '';
for (var k in lineDataMap) {
if (rec != '') {
rec = rec + ';';
}
rec = rec + k;
}
return rec;
}
//----------------------------------------------
//----------------------------------------------
function _tln_analyze_js_create_analyze_data( _FUNC_ID, _FUNC_SEQ, _COL_NAME, _FUNC_KBN, _OPT_SORT, _JS_COMMON , _JS_TEXT , _MOC_NO , _MOC_TEXT , _MOC_SCRIPT) {
putBindVal( 'TLN_ANALYZE_LOG' , '' );
putBindVal( 'TLN_ANALYZE_MOCK_N0', 0 );
if ( ( _MOC_TEXT != '' ) && ( _MOC_TEXT != null ) ) {
tln_write_log("【モックデータ】");
_tln_analyze_mock_data(_MOC_TEXT);
}
if ( ( _MOC_SCRIPT != '' ) && ( _MOC_SCRIPT != null ) ) {
tln_write_log("【モックスクリプト】");
var conv_MOC_SCRIPT = _tln_analyze_js_script_convert( _MOC_SCRIPT );
eval( conv_MOC_SCRIPT ) ;
}
//モック番号の確定(TLN_ANALYZE_INFOにはモック番号毎に分けてデータを格納する)
//チェックがついていない場合はモック番号は0でセット
_tln_analyze_set_mock_no(_MOC_NO);
putBindVal( 'TLN_ANALYZE_MOCK_N0', _tln_analyze_mock_no );
//関連データの初期化(モック番号確定後)
_tln_analyze_js_init(_FUNC_ID, _FUNC_SEQ, _COL_NAME, _FUNC_KBN, _OPT_SORT);
//共通ファンクション読込
var _JS_COMMON_TEXT = '';
//共通JavaScriptを全てで読み込んだときに共通JavaScriptが読みこまれない現象を修正
if (_JS_COMMON == '(全て)') {
if( TALON.getDbConfig().isOra() ) {
//OracleだとそのままSelectするとCLOB型項目を正常に取得できないのでTO_CHARで文字型として取得する
var sql = "" +
"SELECT KEY_CODE,TO_CHAR(NOTE) AS NOTE " +
"FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
"AND KEY_CODE != 'TLN_ANALYZE_COMMON'" + //TLN_ANALYZE_COMMONまで読みこむとeval実行時に循環参照でのStackOverflowにより正常に実行されなくなる
"ORDER BY DSP_SORT1, KEY_CODE" //念のためソート順をログと合わせておく
"";
} else {
var sql = "" +
"SELECT KEY_CODE,NOTE " +
"FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
"AND KEY_CODE != 'TLN_ANALYZE_COMMON'" + //TLN_ANALYZE_COMMONまで読みこむとeval実行時に循環参照でのStackOverflowにより正常に実行されなくなる
"ORDER BY DSP_SORT1, KEY_CODE" //念のためソート順をログと合わせておく
"";
}
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
for (iJSCommonAll = 0; iJSCommonAll < itemSelectList.length; iJSCommonAll++){
var lineDataMap = itemSelectList[iJSCommonAll];
//共通JavaScriptを複数設定したときに最後の共通JavaScriptしか読みこまれない現象を修正
_JS_COMMON_TEXT += "\n" + getMapVal( lineDataMap , 'NOTE' );
}
tln_write_log("【共通ファンクション読込All】" +getMapVal( lineDataMap , 'KEY_CODE' ));
} else {
var _JS_COMMONS = _JS_COMMON.split('\t');
for (var iJSCommon = 0; iJSCommon < _JS_COMMONS.length; iJSCommon++) {
//TLN_ANALYZE_COMMONまで読みこむとeval実行時に循環参照でのStackOverflowにより正常に実行されなくなる
if (_JS_COMMONS[iJSCommon] != '' && _JS_COMMONS[iJSCommon] != 'TLN_ANALYZE_COMMON') {
//OracleだとそのままSelectするとCLOB型項目を正常に取得できないのでTO_CHARで文字型として取得する
if(TALON.getDbConfig().isOra()) {
var sql = "" +
"SELECT TO_CHAR(NOTE) AS NOTE " +
"FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
" AND KEY_CODE = '" + tln_com_escape(_JS_COMMONS[iJSCommon]) + "' " +
"";
} else {
var sql = "" +
"SELECT NOTE " +
"FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
" AND KEY_CODE = '" + tln_com_escape(_JS_COMMONS[iJSCommon]) + "' " +
"";
}
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
if (itemSelectList.length > 0) {
var lineDataMap = itemSelectList[0];
//共通JavaScriptを複数設定したときに最後の共通JavaScriptしか読みこまれない現象を修正
_JS_COMMON_TEXT += "\n" + getMapVal( lineDataMap , 'NOTE' );
}
tln_write_log("【共通ファンクション読込】" + _JS_COMMONS[iJSCommon]);
}
}
}
if ( ( _JS_COMMON_TEXT != '' ) && ( _JS_COMMON_TEXT != null ) ) {
if ( ( _JS_COMMON_TEXT != '' ) && ( _JS_COMMON_TEXT != null ) ) {
tln_write_log("【共通ファンクション】");
var conv_JS_TEXT = _tln_analyze_js_script_convert( _JS_COMMON_TEXT );
eval( conv_JS_TEXT ) ;
}
}
//実行ファンクション読込
if ( ( _JS_TEXT != '' ) && ( _JS_TEXT != null ) ) {
var conv_JS_TEXT = _tln_analyze_js_script_convert( _JS_TEXT );
eval( conv_JS_TEXT ) ;
}
//実行結果ログを出力
putBindVal( 'TLN_ANALYZE_LOG' , _tln_analyze_log );
//EXECUTEのデータの状態を初期化する
_tln_analyze_js_end();
}
function _tln_analyze_js_script_convert(_script) {
var cov_list =[
{moto:'TALON.getConditionData' ,saki:'tln_getConditionData'} ,
{moto:'TALON.getBlockData_Card' ,saki:'tln_getBlockData_Card'} ,
{moto:'TALON.getBlockData_List' ,saki:'tln_getBlockData_List'} ,
{moto:'TALON.getTargetDataIndex' ,saki:'tln_getTargetDataIndex'} ,
{moto:'TALON.getTargetData' ,saki:'tln_getTargetData'} ,
{moto:'TalonDbUtil.select' ,saki:'tln_db_select'} ,
{moto:'TalonDbUtil.insertByMap' ,saki:'tln_db_insertByMap'} ,
{moto:'TalonDbUtil.insertByArray' ,saki:'tln_db_insertByArray'} ,
{moto:'TalonDbUtil.insert' ,saki:'tln_db_insert'} ,
{moto:'TalonDbUtil.updateByMap' ,saki:'tln_db_updateByMap'} ,
{moto:'TalonDbUtil.updateByArray' ,saki:'tln_db_updateByArray'} ,
{moto:'TalonDbUtil.update' ,saki:'tln_db_update'} ,
{moto:'TalonDbUtil.deleteByMap' ,saki:'tln_db_deleteByMap'} ,
{moto:'TalonDbUtil.deleteByArray' ,saki:'tln_db_deleteByArray'} ,
{moto:'TalonDbUtil.delete' ,saki:'tln_db_delete'} ,
]
var tmp_script = _script;
for (var iConvScript = 0; iConvScript < cov_list.length; iConvScript++) {
var cov = cov_list[iConvScript];
var tmp = "tmp_script = tmp_script.replace(/" + cov.moto + "/g, '" + cov.saki + "');";
eval(tmp);
}
TALON.getLogger().writeDebug('★↓↓↓↓変換後スクリプト↓↓↓↓★');
TALON.getLogger().writeDebug(tmp_script);
TALON.getLogger().writeDebug('★↑↑↑↑変換後スクリプト↑↑↑↑★');
return tmp_script;
}
//----------------------------------------------
//----------------------------------------------
//----------------------------------------------
//----------------------------------------------
function tln_getBlockData_Card(block) {
if (_tln_analyze_exec_mode() == '' ) {
var lineDataMap = TALON.getBlockData_Card(block);
} else {
if (_tln_analyze_mock) {
var lineDataMap = _tln_analyze_mock['blocks'][block-1]['blockdata'][0];
} else {
var lineDataMap = null;
}
}
return lineDataMap;
}
function tln_getBlockData_List(block) {
if (_tln_analyze_exec_mode() == '' ) {
var itemBlockList = TALON.getBlockData_List(block);
} else {
if (_tln_analyze_mock) {
var itemBlockList = _tln_analyze_mock['blocks'][block-1]['blockdata'];
} else {
var itemBlockList = null;
}
}
return itemBlockList;
}
function tln_getConditionData() {
if (_tln_analyze_exec_mode() == '' ) {
var lineDataMap = TALON.getConditionData();
} else {
if (_tln_analyze_mock) {
var lineDataMap = _tln_analyze_mock['conditions'];
} else {
var lineDataMap = null;
}
}
return lineDataMap;
}
function tln_getTargetData() {
if (_tln_analyze_exec_mode() == '' ) {
var lineDataMap = TALON.getTargetData();
} else {
if (_tln_analyze_mock) {
var lineDataMap = _tln_analyze_mock['targets']['targetdata'];
} else {
var lineDataMap = null;
}
}
return lineDataMap;
}
function tln_getTargetDataIndex() {
if (_tln_analyze_exec_mode() == '' ) {
var irec = TALON.getTargetDataIndex();
} else {
if (_tln_analyze_mock) {
var irec = _tln_analyze_mock['targets']['targetindex'];
} else {
var irec = null;
}
}
return irec;
}
//----------------------------------------------
function tln_db_select(config, sql) {
var _USER_ID = tln_com_user_id();
var _FUNC_ID = tln_com_func_id();
var _SYSDATE = tln_get_sysdate_created_date(); //tln_com_datetime2string( tln_com_nowdate() );
var itemSelectList = TalonDbUtil.select( config , sql );
if (_tln_analyze_exec_mode() != '' ) {
var tmp = _tln_analyze_select_table_name(sql);
if (itemSelectList.length == 0) {
//データが取得できなかった時はテーブル名だけでセット
_tln_analyze_set_data('ENGINE', tmp , 'SELECT');
} else {
//データが取得できた場合は、その取得情報より項目情報を取得する
var isqTable = 0;
var lineDataMap = itemSelectList[0];
for (var k in lineDataMap) {
var insCount = 0;
var _COL_NAME = k;
var _NAME_ARRAY = tmp.split(';');
for (var iTable = 0; iTable < _NAME_ARRAY.length; iTable++) {
var _TABLE_NAME = _NAME_ARRAY[iTable];
TALON.getLogger().writeDebug('★★★★★' + _TABLE_NAME + ' : ' + _COL_NAME );
//TABLE-COLの組み合わせが有れば、そのテーブル名をセット
var sql = "" +
"SELECT " +
" TABLE_NAME " +
",COLUMN_NAME " +
"FROM TLN_M_NAME_MANAGER " +
"WHERE TABLE_NAME = '" + tln_com_escape(_TABLE_NAME) + "'" +
" AND COLUMN_NAME = '" + tln_com_escape(_COL_NAME ) + "'" +
"";
var itemSelectListTABLECHK = TalonDbUtil.select( TALON.getDbConfig() , sql );
if ( itemSelectListTABLECHK.length == 0 ) {
_TABLE_NAME = '' ;
TALON.getLogger().writeDebug('★★★★★→組み合わせ無し');
} else {
TALON.getLogger().writeDebug('★★★★★→組み合わせ有り');
}
TALON.getLogger().writeDebug('★★★★★⇒' + _TABLE_NAME + ' / ' + iTable + ' / ' + _NAME_ARRAY.length + ' / ' + insCount );
//_TABLE_NAMEがNULLの時はINSERTしない。ただしTABLEの最後のLOOPの時insCountが0の時はNULLに関係なくINSERTする
if ( ( _TABLE_NAME != '' ) || ( ( (iTable + 1) == _NAME_ARRAY.length ) && ( insCount == 0 ) ) ) {
_tln_analyze_set_data_item('ENGINE' , _TABLE_NAME , _COL_NAME , 'SELECT');
insCount = insCount + 1;
}
}
}
}
if (tmp == '') {
tmp = '**解析できませんでした**';
}
tln_write_log("【SELECT】" + tmp);
}
return itemSelectList;
}
function tln_db_insert(config, sql) {
var icount = TalonDbUtil.insert( config , sql );
if (_tln_analyze_exec_mode() != '' ) {
var tmp = _tln_analyze_insert_table_name(sql);
_tln_analyze_set_data('ENGINE', tmp , 'INSERT');
if (tmp == '') {
tmp = '**解析できませんでした**';
}
tln_write_log("【INSERT】" + tmp);
}
return icount;
}
function tln_db_insertByMap(config, table_nm , datalist, coltbl) {
var icount = TalonDbUtil.insertByMap( config , table_nm , datalist , coltbl );
if (_tln_analyze_exec_mode() != '' ) {
var item_nm = _tln_analyze_dataMap_item_name(datalist);
_tln_analyze_set_data_item('ENGINE', table_nm , item_nm , 'INSERT');
tln_write_log("【INSERT】" + table_nm + ' / ' + item_nm);
}
return icount;
}
function tln_db_insertByArray(config, table_nm , datalist_array, coltbl) {
var icount = TalonDbUtil.insertByArray( config , table_nm, datalist_array ,coltbl );
if (_tln_analyze_exec_mode() != '' ) {
var item_nm = _tln_analyze_dataMap_item_name(datalist_array[0]);
_tln_analyze_set_data_item('ENGINE', table_nm , item_nm , 'INSERT');
tln_write_log("【INSERT】" + table_nm + ' / ' + item_nm);
}
return icount;
}
function tln_db_update(config, sql) {
var icount = TalonDbUtil.update( config , sql );
if (_tln_analyze_exec_mode() != '' ) {
var tmp = _tln_analyze_update_table_name(sql);
_tln_analyze_set_data('ENGINE', tmp , 'UPDATE');
if (tmp == '') {
tmp = '**解析できませんでした**';
}
tln_write_log("【UPDATE】" + tmp);
}
return icount;
}
function tln_db_updateByMap(config, table_nm , datalist, coltbl, wherelist) {
var icount = TalonDbUtil.updateByMap( config , table_nm , datalist ,coltbl , wherelist);
if (_tln_analyze_exec_mode() != '' ) {
var item_nm = _tln_analyze_dataMap_item_name(datalist);
_tln_analyze_set_data_item('ENGINE', table_nm , item_nm , 'UPDATE');
tln_write_log("【UPDATE】" + table_nm + ' / ' + item_nm);
}
return icount;
}
function tln_db_updateByArray(config, table_nm , datalist_array, coltbl, wherelist) {
var icount = TalonDbUtil.updateByArray( config , table_nm, datalist_array ,coltbl , wherelist);
if (_tln_analyze_exec_mode() != '' ) {
var item_nm = _tln_analyze_dataMap_item_name(datalist_array[0]);
_tln_analyze_set_data_item('ENGINE', table_nm , item_nm , 'UPDATE');
tln_write_log("【UPDATE】" + table_nm + ' / ' + item_nm);
}
return icount;
}
function tln_db_delete(config, sql) {
var icount = TalonDbUtil.delete( config , sql );
if (_tln_analyze_exec_mode() != '' ) {
var tmp = _tln_analyze_delete_table_name(sql);
_tln_analyze_set_data('ENGINE', tmp , 'DELETE');
if (tmp == '') {
tmp = '**解析できませんでした**';
}
tln_write_log("【DELETE】" + tmp);
}
return icount;
}
function tln_db_deleteByMap(config, table_nm , datalist, wherelist) {
var icount = TalonDbUtil.deleteByMap( config , table_nm, datalist , wherelist);
if (_tln_analyze_exec_mode() != '' ) {
//DELETEは項目情報無し
_tln_analyze_set_data('ENGINE', table_nm , 'DELETE');
tln_write_log("【DELETE】" + table_nm);
}
return icount;
}
function tln_db_deleteByArray(config, table_nm , datalist_array, wherelist) {
var icount = TalonDbUtil.deleteByArray( config , table_nm, datalist_array , wherelist);
if (_tln_analyze_exec_mode() != '' ) {
//DELETEは項目情報無し
_tln_analyze_set_data('ENGINE', table_nm , 'DELETE');
tln_write_log("【DELETE】" + table_nm);
}
return icount;
}
//----------------------------------------------
function tln_write_log(msg) {
TALON.getLogger().writeDebug( msg );
if (_tln_analyze_exec_mode() != '' ) {
if ( _tln_analyze_log != "" ) {
_tln_analyze_log = _tln_analyze_log + '\n';
}
_tln_analyze_log = _tln_analyze_log + msg;
}
}
≣ サーバJS ライブラリTLN_ANALYZE_SETUP 共通JavaScript_リポジトリ分析セットアップ 16376字
/**
* TLN_ANALYZE_COMMON : 共通JavaScript_リポジトリ分析共通部品
*
* 最終更新: TALON_ANALYZE_V1_0_3
* @version 2021/04/09
*/
//--------------------------------------------
// セットアップ関連共通
//--------------------------------------------
function table_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_TABLES WHERE TABLE_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM information_schema.tables WHERE table_name = '" + nm + "' AND table_schema = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'U' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(DISTINCT table_name) AS CNT FROM information_schema.columns WHERE LOWER(table_name) = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function function_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_PROCEDURES WHERE OBJECT_TYPE = 'FUNCTION' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = '" + _DSP1 + "' AND SPECIFIC_NAME = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'FN' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_proc WHERE proname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function view_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_OBJECTS WHERE OBJECT_TYPE = 'VIEW' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '" + nm + "' AND TABLE_SCHEMA = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'V' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_class WHERE relkind = 'v' and relname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function field_exists(nm,fl) {
if ( !TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = '" + nm + "' AND COLUMN_NAME = '" + fl + "' " );
} else {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = LOWER('" + nm + "') AND COLUMN_NAME = LOWER('" + fl + "') " );
}
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function executeSQL(sql) {
if ( TALON.getDbConfig().isOra() ) {
//Oracleの場合true
TALON.executeSQL(sql);
};
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isPostgres() ) {
//Postgresの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
}
function table_exists_drop(nm) {
if (table_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP TABLE " + nm ) ;
} else {
executeSQL( "DROP TABLE " + nm.toLowerCase() ) ;
}
}
}
function function_exists_drop(nm) {
if (function_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP FUNCTION " + nm ) ;
} else {
executeSQL( "DROP FUNCTION " + nm.toLowerCase() ) ;
}
}
}
function view_exists_drop(nm) {
if (view_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP VIEW " + nm ) ;
} else {
executeSQL( "DROP VIEW " + nm.toLowerCase() ) ;
}
}
}
function exec_create_Function() {
//≪FUNCTION DROP≫
//--------------------
//[FUNCTION]
function_exists_drop('XXXXX');
if ( TALON.getDbConfig().isOra() ) {
};
if ( TALON.getDbConfig().isMy() ) {
//SQLファイルで作成
};
if ( TALON.getDbConfig().isMssql() ) {
};
if ( TALON.getDbConfig().isPostgres() ) {
//SQLファイルで作成
};
}
function exec_create_View() {
//≪VIEW DROP≫
//--------------------
//[VIEW]
view_exists_drop('XXXXX');
if ( TALON.getDbConfig().isOra() ) {
};
if ( TALON.getDbConfig().isMy() ) {
//SQLファイルで作成
};
if ( TALON.getDbConfig().isMssql() ) {
};
if ( TALON.getDbConfig().isPostgres() ) {
//SQLファイルで作成
};
}
//--------------------------------------------
// セットアップ後環境別データ修正
//--------------------------------------------
function exec_custom() {
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
if ( chkLowercase() ) {
//lowercaseとして判断
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_KBN = 'UPDATE_TABLE' AND FUNC_ID LIKE 'TLN_ANALYZE_%' ");
}
}
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
var array = ["TLN_CHAR_TO_DATE", "TLN_CHAR_TO_NUMBER", "TLN_CHARINDEX", "TLN_CONCAT", "TLN_DATE_TIME_TO_CHAR", "TLN_DATE_TIME_TO_DATETIME", "TLN_DATE_TO_CHAR", "TLN_DATEADD", "TLN_DATEDIFF", "TLN_FIRSTDAY", "TLN_LEN", "TLN_LF", "TLN_MID", "TLN_ROUND", "TLN_SYSDATE", "TLN_ANALYZE_CONV_CHAR", "TLN_ANALYZE_CONV_TEXT"];
var i;
var num = array.length;
for(i=0;i < num;i++){
//--------------
//TLN_M_GENERAL_FUNC_SQL
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_FUNC_SQL " +
" SET " +
" BODY_SQL = REPLACE(REPLACE(BODY_SQL ,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" ,TITLE_SQL = REPLACE(REPLACE(TITLE_SQL,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' "
);
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_ITEM_OPTN " +
" SET " +
" CHR_TEXT = REPLACE(REPLACE(CHR_TEXT,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_ID <> 'TLN_ANALYZE_SYS01' " +
" AND (FUNC_KBN = 'JAVA_SCRIPT_ENGINE' OR (FUNC_KBN = 'BUTTON_BAT' AND FLAG = 2)) "
);
//--------------
//TLN_M_HANYO_CODE_MAIN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_HANYO_CODE_MAIN " +
" SET " +
" NOTE = REPLACE(REPLACE(NOTE,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
" AND KEY_CODE <> 'TLN_ANALYZE_SETUP' "
);
}
}
if ( TALON.getDbConfig().isPostgres() ) {
//PostgreSQLの場合true
//lower
//--------------
//TLN_M_GENERAL_ITEM
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_ID <> 'TLN_ANALYZE_SYS01' AND COL_NAME <> 'PARAM_FUNC_ID' AND COL_NAME <> 'BLOCK_NO' ");
//--------------
//TLN_M_GENERAL_FUNC_SQL
//機能内で使用しているバインド変数を小文字に変換
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%FUNC_ID%**/' ,'/**%func_id%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%FUNC_SEQ%**/' ,'/**%func_seq%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%FUNC_KBN%**/' ,'/**%func_kbn%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%COL_NAME%**/' ,'/**%col_name%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%OPT_SORT%**/' ,'/**%opt_sort%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%TRG_ID%**/' ,'/**%trg_id%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%TENKAI_HOUKOU%**/' ,'/**%tenkai_houkou%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%SEL_FUNC_ID%**/' ,'/**%sel_func_id%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET TITLE_SQL = REPLACE(TITLE_SQL,'/**%FUNC_KBN%**/' ,'/**%func_kbn%**/' ) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' ");
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = LOWER(CHR4) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace(CHR4,'''jse''','''JSE''') WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND), CHR1 = LOWER(CHR1), CHR_TEXT = LOWER(CHR_TEXT), CHR4 = LOWER(CHR4) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'SEND_MAIL' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND COL_NAME <> 'BLOCK_NO' AND ( FUNC_KBN LIKE 'BUTTON_NEXT_%' or FUNC_KBN = 'INPUT_CONDITION' ) ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1), CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND ( FUNC_KBN = 'SUB_SEARCH' OR FUNC_KBN = 'LOOK_UP' ) ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'REGIST_VALUE' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) , CHR2 = LOWER(CHR2) , CHR3 = LOWER(CHR3) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'SUGGEST' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'FORE_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'INIT_VALUE_TEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'OTHER_FUNC' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1), CHR3 = LOWER(CHR3) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN like 'OTHER_FUNC_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'BACK_COLOR' ");
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND COL_NAME <> 'PARAM_FUNC_ID' AND COL_NAME <> 'BLOCK_NO' AND FUNC_KBN NOT IN ('SEND_MAIL' , 'OTHER_FUNC' , 'JAVA_SCRIPT_ENGINE' , 'JAVA_SCRIPT' , 'BUTTON_NEXT' , 'BUTTON_BAT' , 'BUTTON_AJAX' ) ");
//TLN_M_GENERAL_APP
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_KBN = 'UPDATE_TABLE' ");
//TLN_M_GENERAL_USES
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_USES SET KEY_CODE = LOWER(KEY_CODE) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND USER_CODE = 'TLN_GEN_ALL' AND KEY_CODE NOT IN (' PREVIEW ' , 'JS分析データ収集' ) ");
//--------------
//TLN_M_GENERAL_POSITION
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_POSITION SET NAME = LOWER(NAME) WHERE FUNC_ID LIKE 'TLN_ANALYZE_%' AND FUNC_ID <> 'WFS_M000' AND CHR1='ITEM' ");
}
}
≣ サーバJS ライブラリTLN_ANALYZE_TEST13 共通JavaScript共通ClientsideJavaScriptCSSメンテナンス部品 6293字
function colNameMultiDB(str) {
return TALON.getDbConfig().isPostgres() ? str.toLowerCase() : str;
}
//strを半角スペース、全角スペース、Tabキー入力を区切り文字として分割してセットとして取得する
function splitToSet(str) {
if (!str) return {};
var list = String(str)
.trim()
.split(/[ \u3000\t]+/);
var set = {}; // 疑似Set
for (var i = 0; i < list.length; i++) {
var parts = list[i].split(",");
for (var j = 0; j < parts.length; j++) {
var v = parts[j];
if (v.length > 0) {
set[v] = true;
}
}
}
return set;
}
function listToSet(list) {
var set = {};
for (var i = 0; i < list.length; i++) {
var v = list[i];
set[v] = true;
}
return set;
}
function setToTabString(set) {
// 1. キー一覧取得
var list = Object.keys(set);
// 2. 昇順ソート
list.sort();
// 3. タブ区切りで結合
return list.join("\t");
}
//共通JavaScriptライブラリ入力値、入力項目、行番号、主キー、サーバーサイドクライアントサイドCSSの分類、設定種別コードを取得する
//getLibrarySelectValueAndcolNameAndrowNo()["value"]:入力値
//getLibrarySelectValueAndcolNameAndrowNo()["colName"]:入力項目
//getLibrarySelectValueAndcolNameAndrowNo()["rowNo"]:行番号
function getLibrarySelectValueAndcolNameAndrowNo() {
var lineDataMap = TALON.getTargetData(); //入力値を得たい
var iREC = TALON.getTargetDataIndex(); //更新行番号
var _TYPE_CODE = lineDataMap[colNameMultiDB("TYPE_CODE")];
var librarySelectValue = "";
var updateColName = "";
var updateColNameAll = "";
var resultMap = {};
if(_TYPE_CODE == '0S0' || _TYPE_CODE == '0S1' || _TYPE_CODE == '0S3' || _TYPE_CODE == '1C0' || _TYPE_CODE == '2CS0') { //検索、確定、非同期検索前、Client-side JavaScript、CSS
librarySelectValue = lineDataMap[colNameMultiDB("CHR1")];
updateColName = colNameMultiDB("CHR1");
updateColNameAll = colNameMultiDB("FLAG");
}
if(_TYPE_CODE == '0S2' || _TYPE_CODE == '0S6' ) { //帳票出力、処理呼出
librarySelectValue = lineDataMap[colNameMultiDB("CHR2")];
updateColName = colNameMultiDB("CHR2");
updateColNameAll = colNameMultiDB("CHR1");
}
if(_TYPE_CODE == '0S5') { //JavaScript呼出
librarySelectValue = lineDataMap[colNameMultiDB("CHR2")];
updateColName = colNameMultiDB("CHR2");
updateColNameAll = colNameMultiDB("FLAG");
}
if(_TYPE_CODE == '0S4') { //非同期検索後
librarySelectValue = lineDataMap[colNameMultiDB("CHR5")];
updateColName = colNameMultiDB("CHR5");
updateColNameAll = colNameMultiDB("CHR4");
}
//主キー値も取得する
resultMap["FUNC_ID"] = lineDataMap[colNameMultiDB("FUNC_ID")];
resultMap["FUNC_SEQ"] = lineDataMap[colNameMultiDB("FUNC_SEQ")];
resultMap["COL_NAME"] = lineDataMap[colNameMultiDB("COL_NAME")];
resultMap["FUNC_KBN"] = lineDataMap[colNameMultiDB("FUNC_KBN")];
resultMap["OPT_SORT"] = lineDataMap[colNameMultiDB("OPT_SORT")];
resultMap["value"] = librarySelectValue;
resultMap["colName"] = updateColName;
resultMap["colNameALL"] = updateColNameAll;
resultMap["rowNo"] = iREC;
//共通JavaScriptがサーバーサイドかclient-sideかの場合分けが必要
if( _TYPE_CODE == '1C0' ) {
resultMap['COMMON_TYPE'] = 'CSJS';
} else if ( _TYPE_CODE == '2CS0' ) {
resultMap['COMMON_TYPE'] = 'CSS';
} else {
resultMap['COMMON_TYPE'] = 'SSJS';
}
//設定種別コード
resultMap["TYPE_CODE"] = _TYPE_CODE;
//ライブラリ設定対象外の設定種別(1C1〜1C6等)かどうか
resultMap["hasLibrary"] = (updateColName !== "");
return resultMap;
}
//入力値inputvalueをsplitToSetで分割して全てselectlistに含まれているか確認する
function inputValidator(selectlist,inputvalue) {
var inputvalueset = splitToSet(inputvalue);
var selectset = listToSet(selectlist);
for(key in inputvalueset) {
if (!(key in selectset)) {
return false;
}
}
return true;
}
//JavaScript呼出のサーバーサイドのライブラリ設定がOn click時のレコードにも保存されているため本機能による更新時も同様の処理としておく
function updateCallJavaScriptOnClick() {
var submitRecord = getLibrarySelectValueAndcolNameAndrowNo();
var updatesql = "UPDATE TLN_M_GENERAL_ITEM_OPTN OPTN0 "
+ " SET "
+ colNameMultiDB("CHR4") + " = ( "
+ " SELECT SRC." + colNameMultiDB("CHR2")
+ " FROM ("
+ " SELECT "
+ " OPTN1." + colNameMultiDB("CHR2")
+ " FROM TLN_M_GENERAL_ITEM_OPTN OPTN1"
+ " WHERE "
+ " OPTN1." + colNameMultiDB("FUNC_ID") + " = " + "'" + submitRecord["FUNC_ID"] + "'"
+ " AND OPTN1." + colNameMultiDB("FUNC_SEQ") + " = " + submitRecord["FUNC_SEQ"]
+ " AND OPTN1." + colNameMultiDB("COL_NAME") + " = " + "'" + submitRecord["COL_NAME"] + "'"
+ " AND OPTN1." + colNameMultiDB("FUNC_KBN") + " = " + "'JAVASCRIPT_ENGINE'"
+ " AND OPTN1." + colNameMultiDB("OPT_SORT") + " = " + submitRecord["OPT_SORT"]
+ " ) SRC ) "
+ " , " + colNameMultiDB("FLAG") + " = ( "
+ " SELECT SRC." + colNameMultiDB("FLAG")
+ " FROM ("
+ " SELECT "
+ " OPTN1." + colNameMultiDB("FLAG")
+ " FROM TLN_M_GENERAL_ITEM_OPTN OPTN1"
+ " WHERE "
+ " OPTN1." + colNameMultiDB("FUNC_ID") + " = " + "'" + submitRecord["FUNC_ID"] + "'"
+ " AND OPTN1." + colNameMultiDB("FUNC_SEQ") + " = " + submitRecord["FUNC_SEQ"]
+ " AND OPTN1." + colNameMultiDB("COL_NAME") + " = " + "'" + submitRecord["COL_NAME"] + "'"
+ " AND OPTN1." + colNameMultiDB("FUNC_KBN") + " = " + "'JAVASCRIPT_ENGINE'"
+ " AND OPTN1." + colNameMultiDB("OPT_SORT") + " = " + submitRecord["OPT_SORT"]
+ " ) SRC ) "
+ " WHERE "
+ " OPTN0." + colNameMultiDB("FUNC_ID") + " = " + "'" + submitRecord["FUNC_ID"] + "'"
+ " AND OPTN0." + colNameMultiDB("FUNC_SEQ") + " = " + submitRecord["FUNC_SEQ"]
+ " AND OPTN0." + colNameMultiDB("COL_NAME") + " = " + "'" + submitRecord["COL_NAME"] + "'"
+ " AND OPTN0." + colNameMultiDB("FUNC_KBN") + " = " + "'JAVASCRIPT'"
+ " AND OPTN0." + colNameMultiDB("OPT_SORT") + " = " + submitRecord["OPT_SORT"]
TalonDbUtil.update(TALON.getDbConfig(), updatesql);
}≣ サーバJS ライブラリTLN_FUNC_DOC_COMMON TALON機能設計書出力 共通ライブラリ 712487字
// TLN_FUNC_DOC_COMMON: TALON機能設計書出力 共通サーバ側JS
// LIBRARY_CODE: 0JSENGINE / TYPE: server-side common library
//
// 提供API:
// TFC.getLabelBundle(lang) Java ResourceBundle 取得 (ja/en/zh_CN/...)
// TFC.lbl(bundle, key, fallback) キー→翻訳テキスト
// TFC.escapeHtml(s) HTML エスケープ
// TFC.escapeMd(s) Markdown エスケープ
// TFC.escapeAttr(s) HTML 属性値エスケープ (& < " ' のみ)
// TFC.formatSql(s) SQL 整形 (将来用、現状は trim のみ)
// TFC.appKbnLabel(appKbn, lang) APP_KBN → "固定検索条件"等
// TFC.funcKbnInfo(funcKbn) FUNC_KBN → {section, labelKey, table} (辞書)
// TFC.toLocale(lang) lang 文字列を java.util.Locale へ変換
// TFC.HTML_HEAD / TFC.HTML_TAIL 自己完結HTMLの head/tail 生成
// TFC.htmlSection(title, body, opts) <details>セクション生成
// TFC.tabBadge(isOn, count, lang) タブ on/off バッジ HTML
// TFC.zip(entries) {name: bytes/string} → ZIP バイト列 (java.util.zip)
(function (global) {
'use strict';
var ResourceBundle = Java.type('java.util.ResourceBundle');
var Locale = Java.type('java.util.Locale');
var ByteArrayOutputStream = Java.type('java.io.ByteArrayOutputStream');
var ZipOutputStream = Java.type('java.util.zip.ZipOutputStream');
var ZipEntry = Java.type('java.util.zip.ZipEntry');
var JString = Java.type('java.lang.String');
var Charset = Java.type('java.nio.charset.Charset');
var TFC = {};
// ============================================================
// 言語検出 (V6 のブラウザ言語に応じて出力を切り替える)
// ============================================================
// 出力言語を 'ja' / 'en' で返す。
// V6 (TALON Ver.6.0.2+): ブラウザの Accept-Language が FacesContext.viewRoot.locale に反映される
// → ブラウザ=英語の利用者には英語版を、その他は日本語版を返す
// V5 (TALON Ver < 6.0.2 / Payara 5): FacesContext.viewRoot に locale は載らないため
// 常に 'ja' を返す (V5 で英語対応はしない方針)
TFC.detectLang = function () {
// 検出戦略 (上から優先順):
// (1) TALON.getUserInfoMap().LOCALE — V6.2.7+ で追加されたブラウザ言語 (利用者個別)
// (2) java.util.Locale.getDefault() — JVM デフォルトロケール (Payara JVM オプション
// -Duser.language=en 等で英語化されている環境向け)
// (3) 上記いずれも該当しなければ 'ja'
//
// バージョン別動作:
// - V5 / V6.0.0〜V6.2.6 + JVM=ja: 'ja'
// - V5 / V6.0.0〜V6.2.6 + JVM=en: 'en' (JVM Locale フォールバック)
// ※ V6.0.2〜V6.2.6 でブラウザ言語=en/JVM=ja の組み合わせは英語化できない (TALON 仕様)
// - V6.2.7+ + ブラウザ言語=en: 'en' (利用者ごとに切替)
// - V6.2.7+ + ブラウザ言語=ja: 'ja'
//
// 0S100 は別ワーカースレッドで動くため FacesContext / HttpSession にアクセスできず、
// ブラウザ言語を取得する公式 API は userInfoMap.LOCALE 経由のみ (V6.2.7+)。
// 実機調査 (2026-05-12): V5/V6.2.15 双方で TALON.getUserSessions() / JsfUtil.getUserID()
// 等は worker thread からは "Non-login" を返すため利用できない。
try {
if (typeof TALON !== 'undefined' && typeof TALON.getUserInfoMap === 'function') {
var ui = TALON.getUserInfoMap();
if (ui) {
for (var k in ui) {
if (/^(locale|lang|language)$/i.test(k)) {
var v = String(ui[k] || '');
if (v) {
var nor = _normalizeLang(v);
try { TALON.getLogger().writeInfo('[TFC] detectLang via userInfo[' + k + ']=' + v + ' → ' + nor); } catch (ignore) {}
return nor;
}
}
}
}
}
} catch (e) {}
try {
var dl = Locale.getDefault();
if (dl) {
var lng = String(dl.getLanguage() || '');
if (lng) {
var nor2 = _normalizeLang(lng);
if (nor2 === 'en') {
// ja は既定値と区別がつかないのでログを出すのは en 検出時のみ
try { TALON.getLogger().writeInfo('[TFC] detectLang via Locale.getDefault=' + lng + ' → ' + nor2); } catch (ignore) {}
}
return nor2;
}
}
} catch (e) {}
return 'ja';
};
function _normalizeLang(lng) {
// 'en', 'en-US', 'en_US' → 'en' ; 'ja', 'ja-JP' → 'ja' ; その他は ja にフォールバック
var s = String(lng).toLowerCase().replace('_', '-').split('-')[0];
if (s === 'en' || s === 'ja') return s;
return 'ja';
}
// ============================================================
// ライセンス / エディション (販売プラン ①無償 / ②物理DB+マトリクス / ③全機能)
// ============================================================
// 方式: オフライン署名検証 (RSA-2048 / SHA256withRSA)。
// ・製品には公開鍵のみ埋込 (下記 _LICENSE_PUBKEY_B64)。 署名は弊社の秘密鍵のみで作成可
// (改竄・偽造不可)。 顧客は署名済みライセンスキー (1 行) をファイルに置くだけ:
// {Payara}/glassfish/domains/{domain}/lib/classes/commonweal_license.key
// ★Ver0.63 で製品名に合わせて改名。 旧名 tln_func_doc_license.key も
// フォールバックで読む (既存顧客は置き換え不要 — 公開文書は新名のみ記載)
// ・ライセンスキー形式: base64(payloadJSON) + "." + base64(署名)
// payload = {cid:顧客ID, ed:1|2|3, exp:"YYYY-MM-DD"(当日まで有効), v:版}
// ・未配置 / 無効 / 期限切れ → edition 1 (無償) にフォールバック
// 発行ツール: tools/license_keygen.py (鍵生成・1回) / tools/license_issue.py (顧客ごと)
TFC._LICENSE_PUBKEY_B64 =
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApv8ZGJNXvF6WRq+nHKU3gmjTElQ/Z3+' +
'vSI7z6VGZ8WjL2Zm4UjOS3lrpxc+LtlsfobWuhUwILujjHqoTz3x4zEf5Dx0S+0o/9t0UleI1Uk' +
'485kM2Eg7zfLJDMblyb6WoVC/Cge5mnSWxjWl9gPsZhgRyL0SPUTdFISsOfFSidDK24zSjmdm/6' +
'Neu88Iqaly5QO9N9oWhTml1g+3rNPIzIIvhlvjy4ItVc4OMk/rgRAuxC9EJmXqi6Va3YmXVMHjw' +
'Mxn4E3xN1eBJL9OyDMmSQPKOOvIvWfE8Yzfkfd7W+5PZU+QQQcwMo43HIeUk8ZJf1GNCd7ScQrz' +
'VLXD42l/31wIDAQAB';
TFC.LICENSE_FILE_NAME = 'commonweal_license.key';
// ★Ver0.63 改名前の名前。 既存環境を壊さないため読取のみフォールバックする
TFC.LICENSE_FILE_NAME_LEGACY = 'tln_func_doc_license.key';
// ライセンスキー文字列を検証。 返り値: {valid:bool, edition:1|2|3, cid, exp, reason}
// reason: '' | 'empty' | 'format' | 'badsig' | 'expired' | 'error'
TFC.verifyLicense = function (keyString, todayStr) {
var res = { valid: false, edition: 1, cid: '', exp: '', reason: 'empty' };
if (!keyString) return res;
var ks = String(keyString).replace(/[\r\n\s]/g, '');
if (!ks) return res;
try {
var dot = ks.indexOf('.');
if (dot <= 0) { res.reason = 'format'; return res; }
var msg = ks.substring(0, dot);
var sigB64 = ks.substring(dot + 1);
var Base64 = Java.type('java.util.Base64');
var KeyFactory = Java.type('java.security.KeyFactory');
var X509 = Java.type('java.security.spec.X509EncodedKeySpec');
var Signature = Java.type('java.security.Signature');
var pubDer = Base64.getDecoder().decode(TFC._LICENSE_PUBKEY_B64);
var pub = KeyFactory.getInstance('RSA').generatePublic(new X509(pubDer));
var sig = Signature.getInstance('SHA256withRSA');
sig.initVerify(pub);
sig.update(new JString(msg).getBytes('US-ASCII'));
var sigBytes = Base64.getDecoder().decode(sigB64);
if (!sig.verify(sigBytes)) { res.reason = 'badsig'; return res; }
// 署名 OK → ペイロード復号
var payloadJson = new JString(Base64.getDecoder().decode(msg), 'UTF-8');
var pl = JSON.parse(String(payloadJson));
res.cid = String(pl.cid || '');
res.exp = String(pl.exp || '');
var ed = parseInt(pl.ed, 10);
// 期限判定 (YYYY-MM-DD 文字列比較。 exp >= today で有効)
var today = todayStr || _todayYmd();
if (res.exp && today && res.exp < today) { res.reason = 'expired'; res.edition = 1; return res; }
res.valid = true;
res.edition = (ed === 2 || ed === 3) ? ed : 1;
res.reason = '';
return res;
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] ライセンス検証エラー: ' + e); } catch (ig) {}
res.reason = 'error';
return res;
}
};
function _todayYmd() {
try {
var LD = Java.type('java.time.LocalDate');
return String(LD.now().toString()); // 'YYYY-MM-DD'
} catch (e) {
var d = new Date();
var mm = ('0' + (d.getMonth() + 1)).slice(-2), dd = ('0' + d.getDate()).slice(-2);
return d.getFullYear() + '-' + mm + '-' + dd;
}
}
// ライセンスファイルを lib/classes (talonJdbc.properties と同じ場所) から読む。
// 絶対パスをハードコードせず、 classloader で talonJdbc.properties の位置を解決 →
// 同ディレクトリの commonweal_license.key を毎回フレッシュ読み (差し替え即反映)。
// ★Ver0.63: 新名 commonweal_license.key を優先し、 無ければ旧名
// tln_func_doc_license.key を読む (既存顧客の環境を壊さないための無言フォールバック)。
// 返り値: ライセンスキー文字列 (無ければ '')。
TFC.readLicenseFile = function () {
try {
var File = Java.type('java.io.File');
var Files = Java.type('java.nio.file.Files');
var cl = Java.type('java.lang.Thread').currentThread().getContextClassLoader();
var candidates = [];
var names = [TFC.LICENSE_FILE_NAME, TFC.LICENSE_FILE_NAME_LEGACY];
// 1. talonJdbc.properties と同じ lib/classes を第一候補にする (新名 → 旧名)
try {
var url = cl.getResource('talonJdbc.properties');
if (url) {
var dir = new File(url.toURI()).getParentFile();
for (var n1 = 0; n1 < names.length; n1++) {
candidates.push(new File(dir, names[n1]));
}
}
} catch (e1) {}
// 2. classpath ルート直下 (getResource(license) 直接ヒット。 新名 → 旧名)
try {
for (var n2 = 0; n2 < names.length; n2++) {
var lurl = cl.getResource(names[n2]);
if (lurl) candidates.push(new File(lurl.toURI()));
}
} catch (e2) {}
for (var i = 0; i < candidates.length; i++) {
var f = candidates[i];
if (f && f.exists() && f.isFile()) {
var bytes = Files.readAllBytes(f.toPath());
var text = String(new JString(bytes, 'UTF-8'));
// 自己記述ヘッダ (# 始まりの説明行) と空行を無視して キー本体を取り出す。
// キー本体は '#' で始まらない 1 行 (base64.base64)。 空白は除去。
var flines = text.split(/\r\n|\r|\n/);
var body = '';
for (var fl = 0; fl < flines.length; fl++) {
var ln = flines[fl].replace(/^\s+|\s+$/g, '');
if (ln === '' || ln.charAt(0) === '#') continue;
body += ln;
}
return body;
}
}
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] ライセンスファイル読取エラー: ' + e); } catch (ig) {}
}
return '';
};
// エディションを解決 (1|2|3)。 ファイル読取 → 検証 → 期限判定。 未配置/無効=1 (無償)。
// ログに検出結果を残す (顧客サポート・監査用)。
TFC.resolveEdition = function () {
var keyString = TFC.readLicenseFile();
if (!keyString) {
try { TALON.getLogger().writeInfo('[TFC] ライセンス未配置 → edition 1 (無償)'); } catch (ig) {}
return { edition: 1, license: { valid: false, edition: 1, reason: 'empty' } };
}
var v = TFC.verifyLicense(keyString);
try {
TALON.getLogger().writeInfo('[TFC] ライセンス: valid=' + v.valid + ' edition=' + v.edition +
' cid=' + v.cid + ' exp=' + v.exp + ' reason=' + v.reason);
} catch (ig) {}
return { edition: v.edition, license: v };
};
// ============================================================
// ラベル辞書 (UI 文言)
// ============================================================
// FUNC_KBN_DICT とは別に、HTML/Markdown 出力の見出し・ヘッダ・固定文言を集中管理する。
// key は安定した英数字キー (例: 'sec.funcDesc')、値は言語別の表示文字列。
// 使い方: TFC.t('sec.funcDesc', lang) // → '機能説明' / 'Function Description'
var _labels = {
// セクション見出し / タブ名
'sec.funcDesc': { ja: '機能説明', en: 'Function description' },
'sec.application': { ja: 'アプリケーション', en: 'Application' },
'sec.userGroup': { ja: 'ユーザグループ', en: 'User group' },
'sec.freeLayout': { ja: 'フリーレイアウト', en: 'Free layout' },
'sec.selectExpr': { ja: 'SELECT式', en: 'SELECT formula' },
'sec.titleSelectExpr': { ja: 'タイトルSELECT式', en: 'Title SELECT formula' },
'sec.itemInfo': { ja: '項目情報', en: 'Item information' },
'sec.detailSetting': { ja: '詳細設定', en: 'Detail settings' },
'sec.menuPos': { ja: 'メニュー位置', en: 'Menu position' },
'sec.referenced': { ja: '被参照', en: 'Referenced from' },
'sec.referencedDetail': { ja: '被参照 (他機能から呼ばれている箇所)', en: 'Referenced from (called by other functions)' },
'sec.refGenCd': { ja: '参照汎用CD', en: 'Referenced general code' },
'sec.refSeqNum': { ja: '参照採番', en: 'Referenced numbering' },
'sec.refCalendar': { ja: '参照カレンダー', en: 'Referenced calendar' },
'sec.refClass': { ja: '参照汎用階層', en: 'Referenced general hierarchy' },
'sec.codebook': { ja: 'コードブック', en: 'Code book' },
'sec.deps': { ja: '依存関係', en: 'Dependencies' },
'sec.fixupNotes': { ja: '改修時の注意', en: 'Notes for modification' },
// インデックス / トップレベル
'idx.title': { ja: 'TALON 機能設計書 インデックス', en: 'TALON Function Documents Index' },
'idx.meta.generated': { ja: '生成日時', en: 'Generated' },
'idx.meta.funcCount': { ja: '機能件数', en: 'Function count' },
'idx.col.funcId': { ja: '機能ID', en: 'Function ID' },
'idx.col.funcNm': { ja: '機能名', en: 'Function name' },
'idx.col.outline': { ja: '機能概要', en: 'Outline' },
'idx.col.links': { ja: 'リンク', en: 'Links' },
'idx.uncategorized': { ja: '(未分類)', en: '(Uncategorized)' },
'idx.empty': { ja: '対象機能がありません。', en: 'No target functions.' },
'idx.htmlLink': { ja: 'HTML', en: 'HTML' },
'idx.mdLink': { ja: 'Markdown', en: 'Markdown' },
// 共通テーブルヘッダ
'th.item': { ja: '項目', en: 'Item' },
'th.value': { ja: '値', en: 'Value' },
'th.no': { ja: '#', en: '#' },
'th.type': { ja: 'TYPE', en: 'Type' },
'th.title': { ja: 'TITLE', en: 'Title' },
'th.colName': { ja: 'COL_NAME', en: 'COL_NAME' },
'th.dispName': { ja: 'DISP_NAME', en: 'DISP_NAME' },
'th.tableName': { ja: 'テーブル名', en: 'Table' },
'th.source': { ja: '出典', en: 'Source' },
'th.btnName': { ja: 'ボタン名', en: 'Button name' },
'th.btnLabel': { ja: 'ボタン', en: 'Button' },
'th.kind': { ja: '種別', en: 'Kind' },
'th.state': { ja: '状態', en: 'State' },
'th.group': { ja: 'グループ名', en: 'Group name' },
'th.authKbn': { ja: 'AUTH_KBN', en: 'AUTH_KBN' },
'th.sikibetuCd': { ja: '識別コード', en: 'Identifier code' },
'th.keyCode': { ja: 'KEY', en: 'KEY' },
'th.name': { ja: '名称', en: 'Name' },
// 集約 (検索条件 / 項目情報) のテーブルヘッダ
'th.dispNameTypical': { ja: '表示名 (代表)', en: 'Display name (typical)' },
'th.typicalColName': { ja: '代表 COL_NAME', en: 'Typical COL_NAME' },
'th.typicalBlock': { ja: '代表ブロック', en: 'Typical block' },
'th.aggregatedFrom': { ja: '集約元', en: 'Aggregated from' },
'th.dispName2': { ja: '表示名', en: 'Display name' },
'th.physColName': { ja: '物理項目名', en: 'Physical column' },
'th.component': { ja: 'コンポーネント', en: 'Component' },
'th.dataType': { ja: 'データ型', en: 'Data type' },
'th.dispWidth': { ja: '表示桁', en: 'Display width' },
'th.dispHeight': { ja: '表示高さ', en: 'Display height' },
'th.inputFormat': { ja: '表示・入力形式', en: 'Input format' },
'th.dispOrder': { ja: '表示順', en: 'Display order' },
'th.dispOrderShort': { ja: '並び順', en: 'Order' },
'th.key': { ja: 'キー', en: 'Key' },
'th.update': { ja: '更新', en: 'Update' },
'th.search': { ja: '検索', en: 'Search' },
'th.required': { ja: '必須', en: 'Required' },
'th.digits': { ja: '桁数', en: 'Digits' },
'th.typical': { ja: '代表', en: 'Typical' },
'th.helpUrl': { ja: 'ヘルプURL', en: 'Help URL' },
'th.authGroupId': { ja: '権限グループID', en: 'Auth group ID' },
'th.authKbnLabel': { ja: '権限区分', en: 'Auth kind' },
'th.ref': { ja: '参照', en: 'Ref' },
'th.del': { ja: '削除', en: 'Del' },
'th.funcType': { ja: '機能タイプ', en: 'Function type' },
// 画面ビジュアル内の固定文言
'visual.ref': { ja: '参照', en: 'Ref' },
'visual.del': { ja: '削除', en: 'Del' },
// SUB (検索子画面) モードの専用 UI ラベル (TALON 実画面で観察)
'visual.subSelect': { ja: '選択', en: 'Select' },
'visual.subRowNo': { ja: '行番号', en: 'No.' },
'visual.subRowNoSubMode': { ja: '行番号 (SUB モード)', en: 'Row number (SUB mode)' },
// フォールバック / プレースホルダ
'visual.itemFallback': { ja: '(項目)', en: '(item)' },
'visual.thFallback': { ja: '(TH)', en: '(TH)' },
'visual.tdInputFallback': { ja: '(TD: 入力)', en: '(TD: input)' },
// ボタンエリア (renderFuncAreaFromPos) の標準/カスタムボタン フォールバックチップ
'visual.stdBtnPrefix': { ja: '標準ボタン: ', en: 'Standard button: ' },
'visual.customBtnPrefix': { ja: 'ボタン: ', en: 'Button: ' },
// CSV_LOAD_BUTTON の付随ドロップゾーン widget (TALON 実画面でファイル UI を案内するテキスト)
'visual.csvLoadDropzone': { ja: 'クリックまたはファイルをドロップ', en: 'Click or drop file' },
// 確定ボタン (機能下部) ラベル / 処理実行
'btn.confirm': { ja: '確定', en: 'Confirm' },
'btn.run': { ja: '処理実行', en: 'Run' },
// メタ / 機能カード
'meta.bgCategory': { ja: '業務分類', en: 'Business category' },
'meta.admin': { ja: '管理者', en: 'Administrator' },
'meta.lastUpdate': { ja: '最終更新', en: 'Last update' },
'meta.appKbn': { ja: '機能タイプ', en: 'Function type' },
'meta.notSet': { ja: '(未設定)', en: '(Not set)' },
// タブバッジ
'badge.set': { ja: '設定あり', en: 'set' },
'badge.none': { ja: '設定なし', en: 'none' },
'badge.unit': { ja: '件', en: '' }, // 「2 件」 vs 「2」
// コントロール (HTML 上部のボタン)
'ctrl.allOpen': { ja: '全展開', en: 'Expand all' },
'ctrl.allClose': { ja: '全閉じ', en: 'Collapse all' },
'ctrl.cardOnly': { ja: 'カードのみ', en: 'Cards only' },
'ctrl.onOnly': { ja: '設定ありのみ', en: 'Set only' },
// エラー / 情報メッセージ
'msg.err.noTarget': { ja: '出力対象が選択されていません。明細の「出力対象」にチェックを入れてから押してください。',
en: 'No output target selected. Check "Output target" in the row before pressing.' },
'msg.err.noData': { ja: '対象機能のデータが取得できませんでした。',
en: 'Could not retrieve data for the selected functions.' },
// 出力ファイルのカバーシート/警告
'cov.warnHeader': { ja: '⚠ 注意事項', en: '⚠ Notes' },
// 詳細セクション (Stats / Detail view / Data flow / Reference analysis)
'detail.statsTitle': { ja: '▤ 統計', en: '▤ Statistics' },
'detail.viewTitle': { ja: '⌕ 詳細ビュー (用途で切り替え)', en: '⌕ Detail view (switch by use)' },
'detail.dataFlow': { ja: 'データフロー', en: 'Data flow' },
'detail.refAnalysisTitle':{ ja: '✎ テーブル参照解析について:', en: '✎ About table reference analysis:' },
'detail.refAnalysisMethod':{ ja: 'テーブル参照は <code>UPDATE_TABLE</code> 設定 + ブロック SELECT 式 (BODY_SQL/TITLE_SQL) + 各種 JavaScript コード (CHR_TEXT) + 呼び出すストアドプロシージャの本体 (Oracle / PostgreSQL / MySQL / SQL Server) を <code>FROM</code> / <code>JOIN</code> / <code>INSERT INTO</code> / <code>UPDATE ... SET</code> / <code>DELETE FROM</code> / <code>MERGE INTO</code> / <code>REPLACE INTO</code> / <code>MERGE ... USING</code> のキーワードで正規表現解析した結果です。 動的SQL (EXECUTE IMMEDIATE / PREPARE / sp_executesql 等) は、文字列リテラルが DML 文で始まる場合のみ抽出します。',
en: 'Table references come from regex analysis of <code>UPDATE_TABLE</code> settings, block SELECT formulas (BODY_SQL/TITLE_SQL), JavaScript code (CHR_TEXT) and the body of called stored procedures (Oracle / PostgreSQL / MySQL / SQL Server), looking for <code>FROM</code> / <code>JOIN</code> / <code>INSERT INTO</code> / <code>UPDATE ... SET</code> / <code>DELETE FROM</code> / <code>MERGE INTO</code> / <code>REPLACE INTO</code> / <code>MERGE ... USING</code> keywords. Dynamic SQL (EXECUTE IMMEDIATE / PREPARE / sp_executesql etc.) is extracted only when a string literal starts with a DML statement.' },
'detail.writeLabel': { ja: '書き込み', en: 'Write' },
'detail.readLabel': { ja: '読み取り', en: 'Read' },
'detail.refMissing': { ja: '⚠ 抜け・漏れの可能性', en: '⚠ Possible omissions' },
'detail.refOutOfScope': { ja: '⚠ 対象外', en: '⚠ Out of scope' },
'detail.refWriteDef': { ja: 'INSERT/UPDATE/DELETE/MERGE/REPLACE のいずれかが検出されたテーブル',
en: 'Tables detected by INSERT/UPDATE/DELETE/MERGE/REPLACE' },
'detail.refReadDef': { ja: 'FROM/JOIN のみで参照されているテーブル',
en: 'Tables referenced only by FROM/JOIN' },
'detail.refMissingDesc': { ja: '変数連結でテーブル名を組み立てた SQL は検出できません (リテラルとして完結した動的SQLは抽出します)。JavaScript の if 分岐内の SQL は検出できない場合があります。',
en: 'SQL whose table names are built by variable concatenation cannot be detected (dynamic SQL written as a complete literal is extracted). SQL inside JavaScript if-branches may not be detected.' },
'detail.refScopeDesc': { ja: 'ストアドプロシージャ本体は Oracle / PostgreSQL / MySQL / SQL Server に対応 (DB2 等は今後対応)。 プロシージャから更に呼び出す別プロシージャ、 BODY_SQL/JS に直接書いた CALL/EXEC 呼び出し、 外部 API 経由のアクセス、 トリガで連動するテーブルは含まれません。 動的SQLは文字列リテラルが DML 文で始まる場合のみ抽出し、 変数で組み立てるテーブル名は対象外です。',
en: 'Stored procedure bodies are analyzed for Oracle / PostgreSQL / MySQL / SQL Server (DB2 etc. planned). Procedures called from within a procedure, CALL/EXEC written directly in BODY_SQL/JS, access via external APIs, and tables linked by triggers are not included. Dynamic SQL is extracted only when a string literal starts with a DML statement; table names built from variables are out of scope.' },
'detail.refNoteTag': { ja: '✎ 補完 (備考タグ)', en: '✎ Supplement (Note tags)' },
'detail.refNoteTagDesc': { ja: '解析で捕捉できない依存は、 機能説明タブの備考に [R:テーブル名] (読み) / [W:テーブル名] (書き) / [WR:テーブル名] (読み書き) と記入すると本設計書の依存として取り込まれます (1タグ1テーブル、 文章中に埋め込み可)。 @番号 または @接続名 (talonJdbc.properties の N.jndi.name) で複数DB接続の接続先を明示できます (例 [W:LOG_TBL@2] / [R:PurchaseOrder@jdbc/SapGateway]。 省略時は機能の DB 接続先)。',
en: 'Dependencies the analysis cannot capture can be declared in the Note field of the function description tab as [R:TABLE] (read) / [W:TABLE] (write) / [WR:TABLE] (read+write) — one table per tag, embeddable in plain text. Append @N or @connection-name (the N.jndi.name in talonJdbc.properties) to specify a multi-DB connection target (e.g. [W:LOG_TBL@2] / [R:PurchaseOrder@jdbc/SapGateway]; defaults to the DB connection of the function).' },
'detail.block': { ja: 'ブロック', en: 'Block' },
'detail.wholeFunc': { ja: '機能全体', en: 'Whole function' },
// タブラベル
'tab.deps': { ja: '◈️ 依存関係', en: '◈️ Dependencies' },
'tab.code': { ja: '≣ コードブック', en: '≣ Code book' },
'tab.legacy': { ja: '※ 全設定', en: '※ All settings' },
'tab.domains': { ja: '◇ データドメイン', en: '◇ Data domains' },
// 統計カード
'stats.blocks': { ja: 'ブロック数', en: 'Blocks' },
'stats.code': { ja: 'JS / SQL コード', en: 'JS / SQL code' },
'stats.refFuncs': { ja: '参照先機能', en: 'Referenced functions' },
'stats.refFuncsSub': { ja: 'LOOK_UP/SUB_SEARCH/OTHER_FUNC 等', en: 'LOOK_UP/SUB_SEARCH/OTHER_FUNC etc.' },
'stats.referenced': { ja: '被参照', en: 'Referenced from' },
'stats.referencedSub': { ja: '他機能から呼び出し', en: 'Called from other functions' },
'stats.none': { ja: '(なし)', en: '(none)' },
// 集約 (検索条件 / 項目情報)
'agg.condTitle': { ja: '検索条件集約', en: 'Search condition aggregation' },
'agg.condDesc': { ja: '同一 COL_NAME は自動集約。物理項目名が異なる検索項目は <code>TLN_M_GENERAL_ITEM_OPTN.FUNC_KBN='JOIN'</code> (機能設定画面 アプリケーションタブ「結合項目」) で集約されます。表示名は最初に出現したブロック (SORT 最小) のものを採用。',
en: 'Same COL_NAME values are auto-aggregated. Conditions with different physical column names are aggregated via <code>TLN_M_GENERAL_ITEM_OPTN.FUNC_KBN='JOIN'</code> (Application tab "Join items" in the function setup screen). Display name is taken from the first occurring block (smallest SORT).' },
'agg.countSuffix': { ja: '{0}件 (うち集約あり {1}件)', en: '{0} (with {1} aggregated)' },
'agg.noAggregation': { ja: '(集約なし)', en: '(no aggregation)' },
// ヒーロー (機能カードのタイトル + 機能概要 / 備考)
'hero.outline': { ja: '◆ 機能概要', en: '◆ Outline' },
'hero.note': { ja: '✎ 備考', en: '✎ Note' },
'hero.dataVer': { ja: 'データ版数 (設定の最終更新)', en: 'Data version (last setting update)' },
// 画面ビジュアル (静的画面プレビュー)
'visual.title': { ja: '画面ビジュアル', en: 'Screen visual' },
'visual.hint': { ja: '(各UI要素にマウスオーバーで設定詳細)', en: '(Hover any element to see setting details)' },
'visual.noteTitle': { ja: '✎ 画面イメージの注意事項:', en: '✎ About this visual:' },
'visual.noteBody': { ja: 'この画面イメージは<strong>機能設定 (静的データ) のみ</strong>から組み立てたスケルトンです。実際の動作と異なる場合があります。',
en: 'This visual is a skeleton built from <strong>static settings only</strong>; runtime behavior may differ.' },
'visual.noteDivergeTitle':{ ja: '主な乖離ポイント:', en: 'Main divergences:' },
'visual.noteDiverge1': { ja: '①動的式 (ボタン名表示式 / 条件式 / TITLE_SQL 等) は固定値で表示 — 実行時に評価される。',
en: '① Dynamic expressions (button labels / conditions / TITLE_SQL, etc.) shown with literal text — they are evaluated at runtime.' },
'visual.noteDiverge2': { ja: '②条件付き色付け (FORE_COLOR / BACK_COLOR) は kind 値を直接適用 — 条件式は評価しない。',
en: '② Conditional coloring (FORE_COLOR / BACK_COLOR) applies kind values directly — conditions are not evaluated.' },
'visual.noteDiverge3': { ja: '③カレンダー / ガント / グラフは固定値スケルトン — 実データを反映しない (冪等性担保のため)。',
en: '③ Calendar / Gantt / charts are fixed skeletons — actual data not reflected (for idempotency).' },
'visual.noteDiverge4': { ja: '④ユーザー個別設定 (PDF用紙サイズ等) は固定値表示。',
en: '④ User-individual settings (PDF paper size etc.) shown as fixed values.' },
'visual.noteDiverge5': { ja: '⑤検索 / 確定ボタン押下後の動作は対象外。',
en: '⑤ Post-search / post-confirm behavior is out of scope.' },
// ストーリー (利用シナリオ)
'story.actorUser': { ja: 'ユーザ', en: 'User' },
'story.actorScreen': { ja: '画面', en: 'Screen' },
'story.actorParent': { ja: '親画面', en: 'Parent' },
'story.openFunc': { ja: '機能を開く', en: 'Open the function' },
'story.openFuncTech': { ja: '1C0 LOAD で初期化処理が走ります', en: '1C0 LOAD runs the initialization handler' },
'story.searchInput': { ja: '検索条件を入力 → [検索]ボタン押下', en: 'Enter search conditions → press [Search]' },
'story.searchInputTech': { ja: '0S00 SEARCH_BEFORE → SELECT文発行 → 0S01 SEARCH_AFTER の順で実行',
en: '0S00 SEARCH_BEFORE → issue SELECT → 0S01 SEARCH_AFTER, in order' },
'story.showResults': { ja: '検索結果を明細に表示', en: 'Display search results in the list' },
'story.showResultsTech': { ja: 'ページャあり / 各 LIST ブロックに行を展開',
en: 'With pager; each LIST block is populated with rows' },
'story.editRows': { ja: '明細を編集 (登録/更新/削除)', en: 'Edit rows (insert/update/delete)' },
'story.editRowsTech': { ja: 'FOCUS OUT JavaScript (1C4) でリアルタイム検証',
en: 'FOCUS OUT JavaScript (1C4) provides real-time validation' },
'story.confirm': { ja: '[確定]ボタン押下', en: 'Press [Confirm] button' },
'story.confirmTech': { ja: '0S100 UPDATE_BEFORE → INSERT/UPDATE/DELETE → 0S101 UPDATE_AFTER / 失敗時はロールバック',
en: '0S100 UPDATE_BEFORE → INSERT/UPDATE/DELETE → 0S101 UPDATE_AFTER / rollback on failure' },
'story.batExec': { ja: '[処理実行]ボタン押下 (検索なし)', en: 'Press [Run] button (no search)' },
'story.batExecTech': { ja: 'BUTTON_BAT 系のサーバJSが直接走ります', en: 'BUTTON_BAT server JS runs directly' },
'story.subLaunch': { ja: '当機能を子画面として呼出', en: 'Launch this function as a sub-screen' },
'story.subLaunchTech': { ja: 'SUB_SEARCH/LOOK_UP 経由で起動 → 親画面に値を返却',
en: 'Launched via SUB_SEARCH/LOOK_UP → returns value to the parent' },
'story.flowMain': { ja: 'ユーザ [入力] ──▶ JS処理前 ──▶ SQL発行 ──▶ JS処理後 ──▶ 結果表示',
en: 'User [input] ──▶ Pre-JS ──▶ SQL ──▶ Post-JS ──▶ Render result' },
'story.flowConfirm': { ja: ' └ [確定] ──▶ JS処理前(全体) ──▶ INSERT/UPDATE/DELETE ──▶ JS処理後(全体)',
en: ' └ [Confirm] ──▶ Pre-JS(global) ──▶ INSERT/UPDATE/DELETE ──▶ Post-JS(global)' },
// インデックス: 業務分類未設定
'idx.bgL.unset': { ja: '(業務分類大: 未設定)', en: '(Large category: not set)' },
'idx.bgM.unset': { ja: '(中: 未設定)', en: '(Medium: not set)' },
'idx.bgS.unset': { ja: '(小: 未設定)', en: '(Small: not set)' },
'idx.funcCount': { ja: '出力件数: {0} 機能', en: '{0} functions' },
'idx.summary': { ja: '業務分類 (大 / 中 / 小) ごとにグルーピングし、各グループ内は機能ID 昇順で表示。リンクをクリックすると個別の機能設計書 (HTML / Markdown) が開きます。',
en: 'Grouped by business category (Large / Medium / Small); within each group sorted by Function ID. Click a link to open the function document (HTML / Markdown).' },
'idx.groupCount': { ja: '{0} 機能', en: '{0} functions' },
'idx.writer.title': { ja: 'DB 更新あり', en: 'has DB write' },
// Markdown セクション見出し / TH ラベル群
'md.langCaption': { ja: '言語', en: 'Language' },
'md.dataVer': { ja: 'データ版数 (設定の最終更新)', en: 'Data version (last setting update)' },
'md.funcId': { ja: '機能ID', en: 'Function ID' },
'md.funcNm': { ja: '機能名', en: 'Function name' },
'md.funcType': { ja: '機能タイプ', en: 'Function type' },
'md.adminId': { ja: 'ADMIN_ID', en: 'ADMIN_ID' },
'md.bgL': { ja: '業務分類 大', en: 'Business category (large)' },
'md.bgM': { ja: '業務分類 中', en: 'Business category (medium)' },
'md.bgS': { ja: '業務分類 小', en: 'Business category (small)' },
'md.created': { ja: '作成', en: 'Created' },
'md.lastUpdate': { ja: '最終更新', en: 'Last update' },
'md.outline': { ja: '機能概要', en: 'Outline' },
'md.note': { ja: '備考', en: 'Note' },
'md.none': { ja: '(なし)', en: '(none)' },
'md.noCondItems': { ja: '(条件項目なし)', en: '(no condition items)' },
'md.funcDesc': { ja: '機能説明', en: 'Function description' },
'md.fixupNotes': { ja: '改修時の注意', en: 'Notes for modification' },
'md.menuPos': { ja: 'メニュー位置', en: 'Menu position' },
'md.appSettings': { ja: 'アプリケーション設定', en: 'Application settings' },
'md.appBaseSetting': { ja: '機能レベル設定一覧', en: 'Function-level settings' },
'md.appBaseHint': { ja: 'TLN_M_GENERAL_APP (FUNC_SEQ=-1) に登録されている全ての設定値。非表示フラグや個別セクションで重複して表示される設定も含む。', en: 'All settings stored in TLN_M_GENERAL_APP (FUNC_SEQ=-1). Includes settings also shown in hide-flag table or other sections.' },
'md.btnPosition': { ja: 'ボタン位置移動', en: 'Button positioning' },
'md.btnPositionHint': { ja: 'BUTTON_DSP_POS で設定されたボタンの配置位置とマージン。', en: 'Button placement positions and margins via BUTTON_DSP_POS.' },
'md.btnPositionPos': { ja: '配置位置', en: 'Position' },
'md.btnPositionMargin': { ja: 'マージン (上/下/左/右)', en: 'Margin (T/B/L/R)' },
'md.condAggr': { ja: '検索条件 (集約)', en: 'Search conditions (aggregated)' },
'md.blockSettings': { ja: 'ブロック設定', en: 'Block settings' },
'md.deps': { ja: '依存関係', en: 'Dependencies' },
'md.flPosition': { ja: 'フリーレイアウト POSITION', en: 'Free layout POSITION' },
'md.masters': { ja: 'マスタ参照', en: 'Master references' },
'md.codebook': { ja: 'コードブック', en: 'Code book' },
'md.userGroup': { ja: 'ユーザグループ', en: 'User group' },
'md.hideButtonSetting': { ja: '標準ボタン非表示設定', en: 'Standard button visibility' },
'md.tabHidden': { ja: '非表示', en: 'Hidden' },
'md.tabShown': { ja: '表示', en: 'Shown' },
'md.tabBtn': { ja: 'ボタン', en: 'Button' },
'md.tabState': { ja: '状態', en: 'State' },
'md.btnPdf': { ja: 'PDF出力', en: 'PDF output' },
'md.btnExcel': { ja: 'Excel出力', en: 'Excel output' },
'md.btnExcelUpd': { ja: 'Excel更新', en: 'Excel update' },
'md.btnClear': { ja: 'クリア', en: 'Clear' },
'md.btnSearch': { ja: '検索', en: 'Search' },
'md.btnBack': { ja: '戻る', en: 'Back' },
'md.btnExecute': { ja: '確定', en: 'Confirm' },
'md.btnView': { ja: '参照', en: 'View' },
'md.btnScreenSetting': { ja: '画面設定', en: 'Screen settings' },
'md.btnCondSave': { ja: '検索条件保存', en: 'Save conditions' },
'md.btnCondTitle': { ja: '検索条件タイトル', en: 'Condition title' },
'md.btnBlockName': { ja: 'ブロック名', en: 'Block name' },
'md.refWriteTable': { ja: '参照先テーブル (書き込み)', en: 'Referenced tables (write)' },
'md.refReadTable': { ja: '参照先テーブル (読み取りのみ)', en: 'Referenced tables (read only)' },
'md.refFuncs': { ja: '参照先機能', en: 'Referenced functions' },
'md.refLibs': { ja: '参照先共通ライブラリ', en: 'Referenced shared libraries' },
'md.calledFrom': { ja: '被参照 (呼出元機能)', en: 'Referenced from (caller functions)' },
'md.codeJs': { ja: 'JavaScript / 各種コード', en: 'JavaScript / code' },
'md.codeLibs': { ja: '共通ライブラリ', en: 'Shared libraries' },
'md.cdHanyo': { ja: '汎用CD (TLN_M_HANYO_CODE_MAIN)', en: 'General code (TLN_M_HANYO_CODE_MAIN)' },
'md.cdHanyoClass': { ja: '汎用階層 (TLN_M_HANYO_CLASS)', en: 'General hierarchy (TLN_M_HANYO_CLASS)' },
'md.cdSaiban': { ja: '採番 (TLN_M_SEQ_PARAMETER)', en: 'Numbering (TLN_M_SEQ_PARAMETER)' },
'md.cdCalendar': { ja: 'カレンダー (TLN_M_CALENDAR)', en: 'Calendar (TLN_M_CALENDAR)' },
'md.cdDetail': { ja: '詳細設定', en: 'Detail settings' },
'md.cdItem': { ja: '項目情報', en: 'Item information' },
'md.cdSelectExpr': { ja: 'SELECT 式', en: 'SELECT formula' },
'md.cdBlockComposition': { ja: 'ブロック構成', en: 'Block composition' },
'md.cdCsvOut': { ja: 'CSV出力', en: 'CSV output' },
'md.cdCsvLoad': { ja: 'CSV登録 (▶ クリックまたはファイルをドロップ)',
en: 'CSV upload (▶ Click or drop file)' },
'md.refWarnTitle': { ja: '> **✎ テーブル参照解析の注意事項**\n>\n',
en: '> **✎ Notes on table reference analysis**\n>\n' },
'md.refWarnMethod': { ja: '> - テーブル参照は `UPDATE_TABLE` 設定 + ブロック SELECT 式 (BODY_SQL/TITLE_SQL) + JavaScript コード (CHR_TEXT) + 呼び出すストアドプロシージャ本体 (Oracle / PostgreSQL / MySQL / SQL Server) を `FROM` / `JOIN` / `INSERT INTO` / `UPDATE ... SET` / `DELETE FROM` / `MERGE INTO` / `REPLACE INTO` / `MERGE ... USING` の正規表現で抽出した結果です。 動的SQLは文字列リテラルが DML 文で始まる場合のみ抽出します。\n',
en: '> - Table references come from regex analysis of `UPDATE_TABLE` settings, block SELECT formulas (BODY_SQL/TITLE_SQL), JavaScript (CHR_TEXT) and called stored procedure bodies (Oracle / PostgreSQL / MySQL / SQL Server) for `FROM` / `JOIN` / `INSERT INTO` / `UPDATE ... SET` / `DELETE FROM` / `MERGE INTO` / `REPLACE INTO` / `MERGE ... USING` keywords. Dynamic SQL is extracted only when a string literal starts with a DML statement.\n' },
'md.refWarnDefs': { ja: '> - **書き込み** = INSERT/UPDATE/DELETE/MERGE が検出されたテーブル / **読み取り** = FROM/JOIN のみのテーブル\n',
en: '> - **Write** = tables detected by INSERT/UPDATE/DELETE/MERGE / **Read** = tables referenced only by FROM/JOIN\n' },
'md.refWarnMissing': { ja: '> - **⚠ 抜け・漏れの可能性**: コード内で動的に組み立てられた SQL、変数連結、条件分岐内の SQL は検出できない場合があります。\n',
en: '> - **⚠ Possible omissions**: SQL strings built dynamically by concatenation or in conditional branches may not be detected.\n' },
'md.refWarnScope': { ja: '> - **⚠ 対象外**: ストアドプロシージャ本体は Oracle / PostgreSQL / MySQL / SQL Server に対応 (DB2 等は今後)。 プロシージャから更に呼ぶ別プロシージャ、 BODY_SQL/JS 直書きの CALL/EXEC、 外部 API 経由、 トリガ連動は含まれません。 動的SQLの変数組み立てテーブル名も対象外 (リテラル完結分は抽出)。\n',
en: '> - **⚠ Out of scope**: stored procedure bodies are analyzed for Oracle / PostgreSQL / MySQL / SQL Server (DB2 etc. later). Nested procedure calls, CALL/EXEC written directly in BODY_SQL/JS, external APIs, and triggers are not included. Table names built from variables in dynamic SQL are also out of scope (complete literals are extracted).\n' },
'md.refWarnNoteTag': { ja: '> - **✎ 補完 (備考タグ)**: 解析で捕捉できない依存は 機能説明タブの備考に `[R:テーブル名]` (読み) / `[W:テーブル名]` (書き) / `[WR:テーブル名]` (読み書き) と記入すると依存として取り込まれます (1タグ1テーブル、 文章中に埋め込み可)。 `@番号` または `@接続名` (talonJdbc.properties の N.jndi.name) で複数DB接続の接続先を明示できます (例 `[W:LOG_TBL@2]` / `[R:PurchaseOrder@jdbc/SapGateway]`。 省略時は機能の DB 接続先)。\n\n',
en: '> - **✎ Supplement (Note tags)**: dependencies the analysis cannot capture can be declared in the Note field of the function description tab as `[R:TABLE]` (read) / `[W:TABLE]` (write) / `[WR:TABLE]` (read+write) — one table per tag, embeddable in plain text. Append `@N` or `@connection-name` (the N.jndi.name in talonJdbc.properties) to specify a multi-DB connection target (e.g. `[W:LOG_TBL@2]` / `[R:PurchaseOrder@jdbc/SapGateway]`; defaults to the DB connection of the function).\n\n' },
'md.warnRefMsg': { ja: '> ⚠ この機能は **{0}** 件の参照を他機能から受けています。改修時は呼出元の動作確認が必要です。\n\n',
en: '> ⚠ This function is referenced by **{0}** other functions. Verify the callers when modifying.\n\n' },
'md.libNote': { ja: '_TLN_M_HANYO_CODE_MAIN.SIKIBETU_CODE in (TLN_GENERAL_JAVASCRIPT_ENGINE / TLN_GENERAL_JAVASCRIPT / TLN_GENERAL_CLIENT_JAVASCRIPT / TLN_GENERAL_CSS / TLN_GENERAL_CSS_STR) からマップ。「全て」モード時は該当種別の全ライブラリ、「個別」モード時は CHR1 で指定されたものだけ。_\n\n',
en: '_Mapped from TLN_M_HANYO_CODE_MAIN.SIKIBETU_CODE in (TLN_GENERAL_JAVASCRIPT_ENGINE / TLN_GENERAL_JAVASCRIPT / TLN_GENERAL_CLIENT_JAVASCRIPT / TLN_GENERAL_CSS / TLN_GENERAL_CSS_STR). "All" mode = all libraries of that kind; "Individual" mode = only the one specified by CHR1._\n\n' },
'md.libModeAll': { ja: '[全て]', en: '[All]' },
'md.libModeIndividual': { ja: '[個別]', en: '[Individual]' },
'md.serverJs': { ja: 'サーバ JS', en: 'Server JS' },
'md.clientJs': { ja: 'クライアント JS', en: 'Client JS' },
'md.cssLib': { ja: 'CSS ライブラリ', en: 'CSS library' },
'md.serverJsLib': { ja: 'サーバJS ライブラリ', en: 'Server JS library' },
'md.storedProc': { ja: 'ストアドプロシージャ', en: 'Stored procedure' },
'cb.procPlace': { ja: '設定箇所: ', en: 'Configured at: ' },
'cb.procPlaceConfirmBefore': { ja: '確定処理前プロシージャ', en: 'Pre-confirm procedure' },
'cb.procPlaceConfirmAfter': { ja: '確定処理後プロシージャ', en: 'Post-confirm procedure' },
'cb.procPlaceDlBefore': { ja: '検索前プロシージャ (引出)', en: 'Pre-search procedure (DL)' },
'cb.procPlaceDlAfter': { ja: '検索後プロシージャ (引出)', en: 'Post-search procedure (DL)' },
'cb.procPlaceSearchBefore': { ja: 'DB検索前プロシージャ', en: 'Pre-search procedure' },
'cb.procPlaceSearchAfter': { ja: 'DB検索後プロシージャ', en: 'Post-search procedure' },
'cb.procPlaceBatButton': { ja: '処理呼出ボタン', en: 'Procedure call button' },
'cb.funcLevel': { ja: '機能レベル', en: 'Function level' },
'ofc.resolvedHead': { ja: '呼出先ブロックの解決', en: 'Resolved callee block' },
'ofc.calleeFunc': { ja: '呼出先機能', en: 'Callee function' },
'ofc.calleeBlock': { ja: '呼出先ブロック', en: 'Callee block' },
'ofc.updateTable': { ja: '更新テーブル', en: 'Update table' },
'md.clientJsLib': { ja: 'クライアントJS ライブラリ', en: 'Client JS library' },
'md.fromJoinExtracted': { ja: '_FROM / JOIN 句から抽出_\n\n', en: '_Extracted from FROM / JOIN clauses_\n\n' },
'md.iudExtracted': { ja: '_INSERT/UPDATE/DELETE/MERGE/UPDATE_TABLE 設定_\n\n',
en: '_INSERT/UPDATE/DELETE/MERGE/UPDATE_TABLE settings_\n\n' },
'md.wholeFunc': { ja: '(機能全体)\n\n', en: '(Whole function)\n\n' },
'md.blockNoCol': { ja: 'ブロックNo', en: 'Block#' },
'md.callerFuncId': { ja: '呼出元機能ID', en: 'Caller function ID' },
'md.itemNameCol': { ja: '項目名', en: 'Column name' },
'md.kindCol': { ja: '種別', en: 'Kind' },
'md.settingKindCol': { ja: '設定種別', en: 'Setting kind' },
'md.aggrTitle': { ja: '集約元 ({0}件)', en: 'Aggregated from ({0})' },
'md.notRegistered': { ja: '(マスタ未登録)', en: '(Not in master)' },
'md.sortCol': { ja: '並び', en: 'Sort' },
'md.valueCol': { ja: '値', en: 'Value' },
'md.dispName': { ja: '表示名', en: 'Display name' },
'md.dataType': { ja: 'データ型', en: 'Data type' },
'md.digits': { ja: '桁', en: 'Digits' },
'md.dispFormat': { ja: '表示形式', en: 'Display format' },
'md.crFlg': { ja: '改行', en: 'Line break' },
'md.aggrCount': { ja: '集約数', en: 'Count' },
'md.aggrSrc': { ja: '集約元', en: 'Sources' },
'th.bunrui': { ja: '分類', en: 'Category' },
// === チャート系 (ガント / カレンダー / グラフ) ===
'chart.kind.bar': { ja: '棒', en: 'Bar' },
'chart.kind.line': { ja: '折れ線', en: 'Line' },
'chart.kind.area': { ja: '折れ線エリア', en: 'Line area' },
'chart.kind.spline': { ja: '曲線', en: 'Spline' },
'chart.kind.area_spline': { ja: '曲線エリア', en: 'Spline area' },
'chart.kind.step': { ja: '階段', en: 'Step' },
'chart.kind.area_step': { ja: '階段エリア', en: 'Step area' },
'chart.kind.pie': { ja: '円', en: 'Pie' },
'chart.kind.donut': { ja: 'ドーナツ', en: 'Donut' },
'chart.kind.scatter': { ja: '散布図', en: 'Scatter' },
'chart.bySeries': { ja: ' + 系列別: ', en: ' + by series: ' },
'chart.seriesFields': { ja: '系列項目: ', en: 'Series fields: ' },
'chart.taskCodeLabel': { ja: 'タスクコード=', en: 'Task code=' },
'chart.taskNameLabel': { ja: ' / タスク表示名=', en: ' / Task name=' },
'chart.startLabel': { ja: ' / 開始=', en: ' / Start=' },
'chart.endLabel': { ja: ' / 終了=', en: ' / End=' },
'chart.eventLabel': { ja: ' / イベント: ', en: ' / Event: ' },
'chart.tooltipLabel': { ja: ' ツールチップ=', en: ' Tooltip=' },
'chart.relationLabel': { ja: ' / 関係線: ', en: ' / Relations: ' },
'chart.dispFormulaLabel': { ja: ' / 表示式: ', en: ' / Display formula: ' },
'chart.eventContent': { ja: '内容=', en: 'Content=' },
'chart.calendarCodeLabel': { ja: 'カレンダー識別=', en: 'Calendar code=' },
'th.classCode': { ja: '階層', en: 'Hierarchy' },
'th.taskCode': { ja: 'タスク', en: 'Task' },
'th.saibanKind': { ja: '種別', en: 'Kind' },
'th.saibanKindFix': { ja: '固定値', en: 'Fixed' },
'th.saibanKindAgg': { ja: '集計キー', en: 'Aggregate key' },
'th.saibanKindSeq': { ja: '連番桁数', en: 'Sequence digits' },
// === HTML 細部のラベル / アイコン付き文言 ===
'btn.pdf': { ja: '▦ PDF出力', en: '▦ PDF out' },
'btn.excel': { ja: '▦ Excel出力', en: '▦ Excel out' },
'btn.excelUpdate': { ja: '▦ 更新Excel出力', en: '▦ Update Excel out' },
// V3-5 round7 2026-05-28: 「Excel更新」 (= Excel ファイルを取込みレコード更新) は
// 「更新Excel出力」 (= Excel ファイルを書き出し編集後 取込み) とは別ボタン。
// マスタ #00530: EXCELUPDATE_BUTTON_HDN_FLG は「Excel更新」 側の非表示制御。
'btn.excelImport': { ja: '▦ Excel更新', en: '▦ Excel update' },
'btn.excelMaintain': { ja: 'Excel更新', en: 'Excel update' },
'btn.screenSetting': { ja: '⚙ 画面設定', en: '⚙ Screen settings' },
'btn.clear': { ja: 'クリア', en: 'Clear' },
'btn.search': { ja: '検索', en: 'Search' },
'btn.back': { ja: '戻る', en: 'Back' },
'btn.save': { ja: '保存', en: 'Save' },
'btn.delete': { ja: '削除', en: 'Delete' },
'btn.addRow': { ja: '行追加', en: 'Add row' },
'btn.close': { ja: '✕ 閉じる', en: '✕ Close' },
'visual.hidden': { ja: '✕ 非表示', en: '✕ Hidden' },
'visual.hiddenItem': { ja: '非表示項目 (COMPONENT=HIDDEN または DISP_NAME 空欄)',
en: 'Hidden item (COMPONENT=HIDDEN or DISP_NAME empty)' },
'visual.hiddenItemShort': { ja: '非表示項目', en: 'Hidden item' },
'visual.hiddenByUses': { ja: '表示項目設定で非表示 (TLN_M_GENERAL_USES.LIST 未登録 または FLAG=1)',
en: 'Hidden by display item config (not in TLN_M_GENERAL_USES.LIST or FLAG=1)' },
'visual.toLastRow': { ja: '最終行へ', en: 'Last row' },
'visual.toRowN': { ja: '行目へ', en: 'Go to row' },
'visual.addRow': { ja: '行追加', en: 'Add row' },
'visual.savedCondPh': { ja: '(保存条件名)', en: '(saved name)' },
'visual.initialCond': { ja: '起動時の初期条件にする', en: 'Use as initial conditions' },
'visual.condFreeNote': { ja: '(フリー検索条件)', en: '(free conditions)' },
'visual.condStdNote': { ja: '(検索単票配置)', en: '(single search layout)' },
'visual.condEmpty': { ja: '(条件項目なし)', en: '(no condition items)' },
'visual.condError': { ja: '(検索単票配置データを取得できませんでした)',
en: '(failed to retrieve single search layout)' },
'visual.blockEmpty': { ja: '(項目情報なし)', en: '(no item information)' },
'visual.itemSelect': { ja: '(項目選択)', en: '(select item)' },
'visual.chooseSelect': { ja: '(選択)', en: '(select)' },
'visual.unsetSpan': { ja: '(未設定)', en: '(not set)' },
'visual.searchResultsZero':{ ja: '▼ 検索結果: 0件', en: '▼ Search results: 0' },
'visual.searchCondHead': { ja: '▼ 検索条件', en: '▼ Search conditions' },
'visual.sampleNote': { ja: '※ サンプル描画。実データではありません',
en: '※ Sample render. Not actual data.' },
'visual.sampleNoteGantt': { ja: '※ サンプル描画 (バー描画は固定14日)。',
en: '※ Sample render (bars are fixed 14 days).' },
'visual.sampleRender': { ja: 'サンプル描画', en: 'Sample render' },
'visual.chartType': { ja: 'グラフ種類:', en: 'Chart type:' },
'visual.gantt': { ja: 'ガントチャート', en: 'Gantt chart' },
'visual.calendar': { ja: 'カレンダー', en: 'Calendar' },
'visual.allRowSelect': { ja: '=1: 全選択チェック', en: '=1: Select-all check' },
'visual.delPermission': { ja: '=1: 行削除権限あり', en: '=1: Has delete permission' },
'visual.canHideEq1': { ja: '=1 で非表示可能', en: '=1 to hide' },
'visual.canHideEq1List': { ja: '=1 で非表示可能。明細(LIST)ブロックがある機能のみ表示',
en: '=1 to hide. Shown only for functions with LIST blocks.' },
'visual.subSearch': { ja: '(検索子画面)', en: '(sub-search screen)' },
'visual.libUsageScope': { ja: '使用:', en: 'Used by:' },
'visual.posOrphan': { ja: '(orphan)', en: '(orphan)' },
'visual.emptyCell': { ja: '空きセル', en: 'Empty cell' },
'sec.rawData': { ja: '□ 生データ (DBレコード)', en: '□ Raw data (DB records)' },
'sec.rawPosition': { ja: '□ POSITION テーブル生データ ({0}件)', en: '□ POSITION raw data ({0})' },
'sec.commonLib': { ja: '≣ 共通ライブラリ ({0})', en: '≣ Common libraries ({0})' },
'sec.storedProcCount': { ja: '⛁ ストアドプロシージャ ({0})', en: '⛁ Stored procedures ({0})' },
'sec.serverJsCount': { ja: '■ サーバー側 JS ({0})', en: '■ Server-side JS ({0})' },
'sec.clientJsCount': { ja: '● クライアント JS ({0})', en: '● Client JS ({0})' },
'sec.sqlCount': { ja: '◐ SQL ({0})', en: '◐ SQL ({0})' },
'sec.otherCount': { ja: '⚪ その他 ({0})', en: '⚪ Other ({0})' },
'sec.cellPlacement': { ja: '≡ ブロック内のセル配置 (SCOPE=BLOCK)',
en: '≡ Cell placement inside block (SCOPE=BLOCK)' },
'sec.resultAreaPlacement': { ja: '∠ 結果エリアのブロック配置 (RESULT_AREA)',
en: '∠ Result area block placement (RESULT_AREA)' },
'sec.callerHead': { ja: '⬅ 呼出元', en: '⬅ Called by' },
'sec.refHead': { ja: '参照先 ➡', en: 'References ➡' },
'sec.menuNode': { ja: 'メニュー', en: 'Menu' },
'sec.writeNode': { ja: '書き込み ({0})', en: 'Write ({0})' },
'sec.readNode': { ja: '読み取り ({0})', en: 'Read ({0})' },
'sec.readWriteNode': { ja: '読み書き ({0})', en: 'Read+Write ({0})' },
'sec.tblNotInDb': { ja: 'DB未検出', en: 'Not in DB' },
'sec.tblNotInDbTip': { ja: 'コードからは参照されているが物理 DB に存在しないため ER 図には出力されません', en: 'Referenced by code but not present in the physical DB, so it is not shown in the ER diagram' },
'sec.libsHead': { ja: '≣ 参照先共通ライブラリ', en: '≣ Referenced libraries' },
'sec.itemsAddtl': { ja: '▼ 追加設定 (代表項目)', en: '▼ Additional (typical item)' },
'sec.aggrSrc': { ja: '▼ 集約元 ({0}件)', en: '▼ Aggregated from ({0})' },
'sec.codeNone': { ja: 'JS/SQL コードはありません', en: 'No JS/SQL code.' },
'note.starKey': { ja: '★キー項目', en: '★ Key' },
'note.starUpdate': { ja: '★更新', en: '★ Update' },
'note.starSearch': { ja: '★検索項目', en: '★ Search' },
'note.starUpdateRequired': { ja: '★更新必須', en: '★ Required' },
'note.starCrFlg': { ja: '★改行', en: '★ Line break' },
'note.divider': { ja: '────────', en: '────────' },
'note.additional': { ja: '▼ 追加設定', en: '▼ Additional' },
'note.kbnFlag0': { ja: '0:参照', en: '0: View' },
'note.kbnFlag1': { ja: '1:更新', en: '1: Update' },
'note.unsetMaster': { ja: '<em>未設定</em>', en: '<em>(not set)</em>' },
'pos.fl.helpHint': { ja: '画面の結果エリアを CSS Grid 状に区切り、各セルにブロックを配置する設定です。FUNC_SEQ が指定された行はそのブロックを配置、空欄行はレイアウト用の空セルです。',
en: 'Divides the result area as a CSS Grid; FUNC_SEQ rows place that block, empty rows are layout-only empty cells.' },
'pos.block.cellPlacement': { ja: '各ブロック内部の項目配置 (TH/TDセル) です。POS は階層キー、ROW_NUM/COL_NUM = 配置、ROW_SPAN/COL_SPAN = 結合。TH=ヘッダ・TD=データ。',
en: 'Per-block item placement (TH/TD cells). POS = hierarchy key, ROW_NUM/COL_NUM = position, ROW_SPAN/COL_SPAN = span. TH=header, TD=data.' },
// 機能レベルオプション (renderFuncLevelOptn)
'optn.appReport': { ja: '帳票出力', en: 'Report output' },
'optn.appOtherNext': { ja: '他画面呼出', en: 'Other screen call' },
'optn.appAjax': { ja: '非同期通信', en: 'Async (AJAX)' },
'optn.appSendMail': { ja: '確定後のメール送信', en: 'Send mail after confirm' },
'optn.blockProc': { ja: '処理呼出', en: 'Procedure call' },
'optn.blockReport': { ja: '帳票出力', en: 'Report output' },
'optn.blockOtherNext': { ja: '他画面呼出', en: 'Other screen call' },
'optn.blockFileIo': { ja: 'ファイル入出力', en: 'File I/O' },
'optn.blockOtherFunc': { ja: '他機能呼出', en: 'Other function call' },
// ★Ver1.0.11: EDM 属性のデータドメインは辞書側の EDM 属性宣言だけで決まる (型欄は定義域)。
// 複数のデータドメインから同じ EDM 属性が宣言されているときの警告
'edmw.multiDecl.title': { ja: '複数のデータドメインから宣言されている EDM 属性',
en: 'EDM attributes declared from more than one data domain' },
'edmw.multiDecl.note': { ja: '同じ EDM 属性が複数のデータドメインの「EDM属性」(宣言) に登録されています。設計書は DOMAIN_CD の若い方に結び付けています。業務データ辞書メンテナンスの「EDM属性」タブで、どちらか 1 つのデータドメインにだけ宣言を残してください (EDM属性割当で付け替えることもできます)。',
en: 'The same EDM attribute is declared (EDM attributes tab) on more than one data domain. The document links it to the lowest DOMAIN_CD. Keep the declaration on only one data domain in the EDM attributes tab of the business data dictionary maintenance (or reassign it in EDM attribute assignment).' },
'edmw.multiDecl.resolvedTo': { ja: '結び付け先', en: 'linked to' },
// ER モデル層ライブラリ (TLN_FUNC_DOC_ER) の読み込み確認 (Ver1.0.7)
'erlib.missing': { ja: '共通JS TLN_FUNC_DOC_ER が読み込まれていません。機能のスクリプト設定 (ライブラリ) に TLN_FUNC_DOC_COMMON と一緒に TLN_FUNC_DOC_ER を指定してください',
en: 'The shared library TLN_FUNC_DOC_ER is not loaded. Add TLN_FUNC_DOC_ER next to TLN_FUNC_DOC_COMMON in the script settings (libraries) of the function' },
'erlib.old': { ja: '共通JS TLN_FUNC_DOC_ER (版 {0}、API {1}) が古く、本体 (API {2}) と合いません。TLN_FUNC_DOC_ER を更新してください',
en: 'The shared library TLN_FUNC_DOC_ER (version {0}, API {1}) is too old for this product (API {2}). Update TLN_FUNC_DOC_ER' },
// EDM メンテナンスの直接アップロード (Ver1.0.7): 確定メッセージ
'edmUp.done': { ja: '{0}: {1} を .a5er に変換して登録しました (エンティティ {2} / 属性 {3} / リレーションシップ {4})',
en: '{0}: converted {1} to .a5er (entities {2} / attributes {3} / relationships {4})' },
'edmUp.warn': { ja: '{0}: 変換の警告 {1} 件 — {2}', en: '{0}: {1} conversion warning(s) — {2}' },
'edmUp.failed': { ja: '{0}: {1} を .a5er に変換できませんでした ({2})',
en: '{0}: could not convert {1} to ' },
'edmUp.unsupported': { ja: '{0}: {1} は対応していない形式です (.a5er / .edm / .vsdx / .asta を指定してください)。EDM モデルは作られません',
en: '{0}: {1} is not a supported format (use .a5er / .edm / .vsdx / .asta). No EDM model is derived' },
'edmUp.noCol': { ja: 'EDM モデルの列 (TLN_M_FUNC_EDM.MODEL_FILE) がありません。セットアップを再実行してください',
en: 'The EDM model column (TLN_M_FUNC_EDM.MODEL_FILE) is missing. Run the setup again' },
// EDM.html の属性表 (Ver1.0.11): 定義域 (ツールのドメイン名・型・コメント) と データドメイン (宣言による結び付き)
'edm.th.domainDef': { ja: '定義域', en: 'Domain (type)' },
'dom.edmAttrs.attrComment': { ja: '属性のコメント', en: 'Attribute comment' }, // 2026-10-02 案 A: Domains.html の EDM 属性 (宣言) に属性のコメント
// ---- EDM属性CSV一括登録 (TLN_FUNC_DOC_DOMAIN_EDM_BULK、 Ver1.0.22) の確定前チェック ----
'edmBulk.domainCdRequired.err': { ja: '{0} 行目: データドメインコードを入力してください', en: 'Row {0}: enter the data domain code' },
'edmBulk.domainNotFound.err': { ja: '{0} 行目: データドメインコード「{1}」は存在しません', en: 'Row {0}: data domain code "{1}" does not exist' },
'edmBulk.edmAttrRequired.err': { ja: '{0} 行目: EDM属性を入力してください (属性名 または エンティティ.属性名)', en: 'Row {0}: enter the EDM attribute (attribute or entity.attribute)' },
'edmBulk.edmAttrOne.err': { ja: '{0} 行目: EDM属性「{1}」は 1 行に 1 つだけ書いてください (カンマ区切りの複数は不可)', en: 'Row {0}: write one EDM attribute per row ("{1}" has several)' },
'edmBulk.edmAttrDup.err': { ja: '{0} 行目: EDM属性「{1}」は同じデータドメイン内で重複しています', en: 'Row {0}: EDM attribute "{1}" is duplicated within the data domain' },
'edmBulk.edmAttrDupDb.err': { ja: '{0} 行目: EDM属性「{1}」は既存の宣言「{2}」と表記だけが違う同じ宣言です (既存の表記に揃えてください)', en: 'Row {0}: EDM attribute "{1}" is the same declaration as the existing "{2}" with different spelling (use the existing spelling)' },
'edm.th.dataDomain': { ja: 'データドメイン', en: 'Data domain' },
'edm.badge.unset': { ja: '未設定', en: 'unset' },
'edm.badge.multiDecl': { ja: '複数の宣言', en: 'multiple declarations' },
'edm.badge.defVaries': { ja: 'EDM で異なる', en: 'differs by EDM' }, // Ver1.0.22 (No.204)
'edm.badge.defVariesTitle': { ja: '同じエンティティ名の EDM で、 この属性の定義域 (ドメイン名・型) が違います。 「 / 」で全部を並べています (印の上に EDM 名)', en: 'EDMs with the same entity name give this attribute different domains (name / type); all are listed separated by " / " (hover for the EDM name)' },
'edm.badge.multiDeclTitle': { ja: '複数のデータドメインの「EDM属性」タブで宣言されています。DOMAIN_CD の若い方に結び付けました (業務データ辞書メンテナンスの EDM属性タブで 1 つに)', en: 'Declared in the EDM attributes tab of more than one data domain; linked to the lowest DOMAIN_CD (keep one in the dictionary maintenance)' },
// 物理属性名が空 (実装未定) の属性行の表示
'dom.attrPlaceholder': { ja: '実装未定', en: 'not implemented yet' },
// 辞書カードの「EDM 属性 (宣言)」(Ver1.0.11): 宣言で結び付いた EDM 属性と、 その定義域
'dom.edmAttrs.title': { ja: 'EDM 属性 (宣言)', en: 'EDM attributes (declared)' },
'dom.edmAttrs.none': { ja: 'EDM 属性が宣言されていません', en: 'No EDM attribute is declared' },
'dom.edmAttrs.domain': { ja: '定義域', en: 'domain' },
// 辞書メンテ / 属性CSV一括登録 の確定前チェック (Ver1.0.11): 物理属性名か EDM属性のどちらかは必須
// Ver1.0.14: 物理属性名は必須に戻した (宣言だけの行は無い — 宣言は「EDM属性」タブ = TLN_M_FUNC_DOMAIN_EDM_DEF)。 同じデータドメイン内の同名はエラー
'mainte.attrNmRequired.err': { ja: '属性の {0} 行目: 物理属性名を入力してください', en: 'Attribute row {0}: enter the physical attribute name' },
'mainte.attrNmDup.err': { ja: '属性の {0} 行目: 物理属性名「{1}」は同じデータドメイン内で重複しています', en: 'Attribute row {0}: physical attribute name "{1}" is duplicated within the data domain' },
'mainte.attrNmDupDb.err': { ja: '属性の {0} 行目: 物理属性名「{1}」は同じデータドメインに登録済みです', en: 'Attribute row {0}: physical attribute name "{1}" already exists in the data domain' },
'mainte.edmDefDup.err': { ja: 'EDM属性の {0} 行目: 「{1}」は同じデータドメイン内で重複しています', en: 'EDM attribute row {0}: "{1}" is duplicated within the data domain' },
'bulk.trimmed.err': { ja: '{0} 行目: {1}「{2}」の前後に空白があります。空白を除いて取り込んでください', en: 'Row {0}: {1} "{2}" has leading or trailing spaces; remove them and import again' },
'bulk.counts.info': { ja: '新規 {0} 件 / 更新 {1} 件 (キーが登録済みの行は更新、それ以外は採番して新規に登録します。更新のつもりの行が新規に数えられていたらキーを確かめてください)', en: 'New: {0} / updated: {1} (rows whose key exists are updated; the others are registered as new with a generated key. If a row you meant to update is counted as new, check its key)' },
'bulk.keyDupInFile.err': { ja: '{0} 行目: データドメインコード「{1}」と属性NO「{2}」の組が {3} 行目と重複しています (後の行で上書きされるため取り込めません)', en: 'Row {0}: data domain code "{1}" + attribute no. "{2}" duplicates row {3} (the later row would overwrite it)' },
'bulk.domainCdDupInFile.err': { ja: '{0} 行目: データドメインコード「{1}」が {2} 行目と重複しています (後の行で上書きされるため取り込めません)', en: 'Row {0}: data domain code "{1}" duplicates row {2} (the later row would overwrite it)' },
'bulk.mainNmBlank.err': { ja: '{0} 行目: データドメイン名称が空白だけです', en: 'Row {0}: the data domain name is blank' },
'bulk.mainNmDupInFile.warn': { ja: '{0} 行目: データドメイン名「{1}」は {2} 行目にもありますが、プロジェクトが重ならないため両方登録します', en: 'Row {0}: data domain name "{1}" also appears in row {2}; both are registered because their projects do not overlap' },
'bulk.emptyAttrRowsSkipped': { ja: '物理属性の無いデータドメインの空の行 {0} 行は取り込みの対象外にしました', en: 'Skipped {0} empty row(s) of data domains without physical attributes' },
'assign.commentNoDomain.warn': { ja: 'データドメインが未設定の {0} 行のコメントは保存しません (コメントはデータドメインへの宣言に付くものです。データドメインと一緒に入力してください)', en: 'The comment of {0} row(s) without a data domain was not saved (a comment belongs to the declaration under a data domain; enter it together with the data domain)' },
'assign.newDisjoint.info': { ja: '(参考) {0}: 「{1}」はプロジェクトが重ならない別のデータドメインにもあります ({2})。このプロジェクト用に別のデータドメインとして新しく作成しました', en: '(FYI) {0}: \"{1}\" also exists as a data domain in a project that does not overlap ({2}); a separate data domain was created for this project' },
'assign.defCleared': { ja: 'EDM 属性のコメントを {0} 件消しました', en: 'Cleared the comment of {0} EDM attribute(s)' },
'assign.entOverrideKept.warn': { ja: '属性名「{0}」のエンティティ別の宣言 ({1} 件: {2}) はそのまま残ります。エンティティ別の宣言は属性名の宣言より優先されるので、上書きするにはエンティティ別タブで割り当て直してください', en: 'The entity-level declarations of attribute "{0}" ({1}: {2}) are kept; they take precedence over the attribute-name declaration, so reassign them in the by-entity tab to override' },
'mainte.edmAttrDup.info': { ja: '(参考) {0}: EDM属性「{1}」は別プロジェクトのデータドメイン ({2}) からも宣言されています (プロジェクトが重ならないため警告ではありません)', en: '(FYI) {0}: EDM attribute "{1}" is also declared by a data domain of a different project ({2}); not a warning because the projects do not overlap' },
'mainte.edmAttrIncl.warn': { ja: '{0}: EDM属性「{1}」は {2} の宣言と包含関係にあります (「エンティティ.属性」の宣言が「属性」の宣言より優先されます)', en: '{0}: EDM attribute "{1}" overlaps the declaration(s) {2} (an "Entity.Attribute" declaration takes precedence over an "Attribute" one)' },
'mainte.edmAttrIncl.self.warn': { ja: '{0}: EDM属性「{1}」は同じデータドメインの「{2}」と包含関係にあります (修飾した宣言が優先されるので、同じデータドメインでは片方で足ります)', en: '{0}: EDM attribute "{1}" overlaps "{2}" in the same data domain (the qualified declaration takes precedence; one of them is enough in the same data domain)' },
'mainte.edmAttrIncl.info': { ja: '(参考) {0}: EDM属性「{1}」は別プロジェクトの宣言 {2} と包含関係にあります (プロジェクトが重ならないため警告ではありません)', en: '(FYI) {0}: EDM attribute "{1}" overlaps the declaration(s) {2} of a different project; not a warning because the projects do not overlap' },
'mainte.declCanon.msg': { ja: 'EDM属性の宣言 {0} 件の綴りを EDM の属性名に揃えました: {1}', en: 'Aligned the spelling of {0} EDM attribute declaration(s) with the EDM attribute names: {1}' },
'mainte.orphanDefPruned': { ja: '物理属性から外れて使われなくなった EDM 属性の宣言 {0} 件を消しました: {1} (コメントの付いた宣言は残します)', en: 'Removed {0} EDM attribute declaration(s) no longer implemented by any physical attribute: {1} (declarations with a comment are kept)' },
'bulk.mainNmDupInFile.err': { ja: '{0} 行目: データドメイン名「{1}」が {2} 行目と重複しています (同じプロジェクト)', en: 'Row {0}: data domain name "{1}" duplicates row {2} (same project)' },
// EDM属性割当 (TLN_FUNC_DOC_EDM_ATTR_ASSIGN) の確定メッセージ
'assign.done': { ja: 'EDM 属性 {0} 件をデータドメインに結び付けました', en: 'Linked {0} EDM attribute(s) to data domains' },
'assign.created': { ja: 'データドメインを新規作成しました: {0}', en: 'Created data domains: {0}' },
'assign.moved': { ja: '付け替え {0} 件 (以前の宣言と物理属性の行を新しいデータドメインへ移しました)', en: 'Reassigned {0} (previous declarations and physical attribute rows moved to the new data domain)' },
// Ver1.0.14: 辞書側の定義域 (型 / 桁 / 定義域コメント) の更新
'assign.defUpdated': { ja: 'EDM 属性のコメントを {0} 件更新しました', en: 'Updated the comment of {0} EDM attribute(s)' },
'assign.ambiguous': { ja: '{0}: 「{1}」は同名のデータドメインが複数あります。候補から選び直してください', en: '{0}: several data domains are named "{1}"; pick one from the suggestions' },
'assign.none': { ja: 'データドメイン名が入力された行がありません', en: 'No row has a data domain name entered' },
// Ver1.0.13: 辞書側の確定 (メンテナンス / 属性CSV一括登録) で、 同じ EDM 属性が他のデータドメインからも宣言されているとき
'mainte.edmAttrDup.warn': { ja: '{0}: EDM属性「{1}」は他のデータドメイン ({2}) からも宣言されています。基本方針は 1 つの EDM 属性に 1 つのデータドメインです (設計書では DOMAIN_CD の若い方に結び付き、警告に出ます)',
en: '{0}: EDM attribute "{1}" is also declared by other data domain(s) ({2}). The rule is one data domain per EDM attribute (the document links to the lowest DOMAIN_CD and warns)' },
'assign.noEdmAttr': { ja: '{0}: EDM 属性が特定できません (再検索してください)', en: '{0}: cannot identify the EDM attribute (search again)' },
// Ver1.0.16: 2 タブ (属性名で集約 / エンティティ別) — 確定メッセージの行ラベル
'assign.tabAttr': { ja: '属性名別', en: 'by attribute' },
'assign.tabEnt': { ja: 'エンティティ別', en: 'by entity' },
'assign.noDefTable': { ja: '宣言の表 (TLN_M_FUNC_DOMAIN_EDM_DEF) がありません。セットアップを実行してください', en: 'The declaration table (TLN_M_FUNC_DOMAIN_EDM_DEF) is missing. Run the setup first' },
// Ver1.0.15: 宣言のコメント (辞書側)。 定義域 (型・桁) はモデルのものだけ — 辞書側の型・桁の補完は廃止 (ユーザー決定 2026-09-26)
'dom.edmAttrs.comment': { ja: 'コメント', en: 'comment' },
// Ver1.0.6: 辞書カードの「改訂履歴」
'dom.hist.title': { ja: '改訂履歴', en: 'Revision history' },
'dom.hist.more': { ja: 'ほか {0} 版', en: '{0} more' },
'dom.hist.kbn.I': { ja: '新規', en: 'added' },
'dom.hist.kbn.U': { ja: '更新', en: 'updated' },
'dom.hist.kbn.D': { ja: '削除', en: 'deleted' },
'dom.hist.kbn.S': { ja: '初期取込', en: 'initial import' },
'dom.hist.kbn.N': { ja: '変更なし', en: 'unchanged' },
// EDM の版の「変更内容」(TFC.edmModelDiffText、 確定時に環境言語で書いて履歴に保存)
'edmhis.diff.summary': { ja: 'エンティティ {0} / 属性 {1}', en: '{0} entities / {1} attributes' },
'edmhis.diff.entAdd': { ja: 'エンティティ追加', en: 'Entities added' },
'edmhis.diff.entDel': { ja: 'エンティティ削除', en: 'Entities removed' },
'edmhis.diff.attrAdd': { ja: '属性追加', en: 'attributes added' },
'edmhis.diff.attrDel': { ja: '属性削除', en: 'attributes removed' },
'edmhis.diff.domChg': { ja: '定義域変更', en: 'domain (type) changed' },
'edmhis.diff.layoutOnly': { ja: 'エンティティ・属性の変更なし (配置などの変更)', en: 'No entity/attribute changes (layout or other edits)' },
// ★テスター指摘 No.131 (Ver0.56): データドメイン名称の同名重複は確定をブロックする
// (未登録のドメインを 2 人が同時に「書く」と同名が 2 件できてしまうため)
// ★Ver0.57: プロジェクト集合が重なる相手のときだけブロックする (重ならなければ警告)
// {0}=入力したデータドメイン名称 {1}=既存側 (名称 [DOMAIN_CD] (プロジェクト) の一覧)
'dom.dupMainNm.err': { ja: 'データドメイン名称「{0}」は既に登録されているため確定できません: {1} — 既存のデータドメインを検索して編集してください (プロジェクトが重ならない場合のみ同名を登録できます)',
en: 'Cannot save: the data domain name "{0}" is already registered: {1} — search for the existing data domain and edit it instead (the same name is allowed only when the projects do not overlap).' },
// ★Ver0.57: 同名だが プロジェクトが重ならない = 別コンテキストの別概念として登録を許す
// {0}=相手のプロジェクト名 {1}=データドメイン名称 {2}=相手の DOMAIN_CD
'dom.dupMainNm.warn': { ja: '他のプロジェクト({0})には同名のデータドメイン「{1}」({2})が存在しますが、プロジェクトが重ならないため登録します',
en: 'Another project ({0}) has a data domain with the same name "{1}" ({2}), but the projects do not overlap, so this one is registered.' },
// 同名判定の相手側ラベルで使う「プロジェクト未設定」(= 全プロジェクトと重なる) の表記
'dom.dupMainNm.noProj': { ja: 'プロジェクト未設定', en: 'no project' },
// クライアントサイド (app.client.js 用)
'cli.dlReady': { ja: '機能設計書 ZIP の準備ができました',
en: 'Function Documents ZIP is ready' },
'cli.dlButton': { ja: '▼ {0} をダウンロード',
en: '▼ Download {0}' },
'cli.dlStarted': { ja: '✓ ダウンロードを開始しました',
en: '✓ Download started' },
'cli.dlMarkerCleaned': { ja: '機能設計書ZIPの準備が完了しました: {0}',
en: 'Function Documents ZIP prepared: {0}' },
// サーバ側出力 (Ver1.0.1): 出力履歴の一覧 index.html / 確定時メッセージ
'sv.title': { ja: 'Commonweal 設計書出力の履歴', en: 'Commonweal design document outputs' },
'sv.intro': { ja: '設計書出力をサーバに保存した履歴です(新しい順)。各行の「開く」で成果物のホームを開きます。',
en: 'Design document outputs saved on this server, newest first. Click "Open" to view the output home page.' },
'sv.count': { ja: '{0}件', en: '{0} runs' },
'sv.col.datetime': { ja: '出力日時', en: 'Output time' },
'sv.col.user': { ja: '利用者', en: 'User' },
'sv.col.funcs': { ja: '出力した機能', en: 'Functions' },
'sv.col.conditions': { ja: '検索条件', en: 'Search conditions' },
'sv.col.lang': { ja: '言語', en: 'Language' },
'sv.col.edition': { ja: 'プラン', en: 'Plan' },
'sv.col.open': { ja: '成果物', en: 'Output' },
'sv.open': { ja: '開く', en: 'Open' },
'sv.funcCount': { ja: '{0}機能', en: '{0} functions' },
'sv.funcMore': { ja: '他{0}件を表示', en: 'Show {0} more' },
'sv.noCondition': { ja: '(条件指定なし)', en: '(no conditions)' },
'sv.project': { ja: 'プロジェクト', en: 'Project' },
'sv.files': { ja: '{0}ファイル', en: '{0} files' },
'sv.zip': { ja: 'ZIPをダウンロード', en: 'Download ZIP' },
'sv.col.cmp': { ja: '差分', en: 'Diff' }, // 2026-10-14: 一覧から 2 世代を選んで差分設計書
'sv.cmp.title': { ja: '2つの出力を選んで差分設計書を開く', en: 'Pick two outputs and open the design-doc diff' },
'sv.cmp.old': { ja: '旧', en: 'Old' },
'sv.cmp.new': { ja: '新', en: 'New' },
'sv.cmp.run': { ja: '差分を見る', en: 'Show diff' },
'sv.cmp.help': { ja: '各行の「旧」「新」を1つずつ選んで押すと、新しい方の差分設計書 (Compare.html) がサーバ上の2つのZIPを読んで比較します。',
en: 'Choose one Old and one New row and press: the newer output\'s Compare.html loads both ZIPs from the server and compares them.' },
'sv.cmp.need': { ja: '「旧」と「新」を1つずつ、別々の行で選んでください。', en: 'Choose one Old and one New on different rows.' },
'sv.mdZip': { ja: 'AI向けMarkdown (ZIP)', en: 'Markdown for AI (ZIP)' },
'sv.empty': { ja: 'まだ出力はありません。', en: 'No outputs yet.' },
'sv.edition1': { ja: '① 無償', en: 'Free' },
'sv.edition2': { ja: '② 物理DB', en: 'Physical DB' },
'sv.edition3': { ja: '③ 全機能', en: 'Full' },
'sv.lang.ja': { ja: '日本語', en: 'Japanese' },
'sv.lang.en': { ja: '英語', en: 'English' },
// 検索条件キー → 表示名 (一覧の「検索条件」列。 未知のキーは物理名のまま。 動的参照 'cond.' + キー)
'cond.FUNC_ID': { ja: '機能ID', en: 'Function ID' },
'cond.FUNC_ID_IN': { ja: '機能ID(IN)', en: 'Function ID (IN)' },
'cond.FUNC_ID_LIKE': { ja: '機能ID(部分一致)', en: 'Function ID (partial)' }, // Ver1.0.18: 部分一致に統一 (素の「機能ID」は明細の列名と重複して CMN_E0139)
'cond.FUNC_NM': { ja: '機能名', en: 'Function name' },
'cond.APP_KBN': { ja: 'アプリケーション区分', en: 'Application type' },
'cond.BG_L': { ja: '業務分類(大)', en: 'Business category (L)' },
'cond.BG_M': { ja: '業務分類(中)', en: 'Business category (M)' },
'cond.BG_S': { ja: '業務分類(小)', en: 'Business category (S)' },
'cond.FUNC_OUTLINE': { ja: '機能概要', en: 'Function outline' },
// ★完了メッセージにはサーバの物理パスを出さない (テスター指摘 No.146)。 {0} = 世代フォルダ名 (yyyyMMdd_HHmmss)。
// 物理パスと失敗の詳細 (例外の文言にはパスが含まれる) はサーバログ [TFC] server out にだけ残す
'msg.serverOutDone': { ja: 'サーバに保存しました (出力フォルダ: {0})', en: 'Saved on the server (output folder: {0})' },
'msg.serverOutFailed': { ja: 'サーバへの保存に失敗したため、ZIPダウンロードのみ行います。詳細はサーバのログを確認してください',
en: 'Saving on the server failed, so only the ZIP download is provided. See the server log for details.' },
// 全文検索 (Ver1.0.5) — 検索バー / 結果パネルの文言 (出力言語で埋め込む)
'search.title': { ja: '⌕ 全文検索', en: '⌕ Full-text search' },
'search.placeholder': { ja: '出力した設計書群を全文検索 ― 「/」キーでこの欄へ、Enter で検索、Esc で閉じる',
en: 'Search all generated documents — press "/" to focus, Enter to search, Esc to close' },
'search.lib': { ja: 'ライブラリのソース全文も対象にする', en: 'Include library sources' },
'search.loading': { ja: '索引を読み込んでいます…', en: 'Loading the index…' },
'search.loadError': { ja: '索引 (search-index.js) を読み込めませんでした', en: 'Could not load the index (search-index.js)' },
// ★Ver1.0.23: 知識グラフ エクスプローラ (Graph.html)
'graph.title': { ja: '知識グラフ エクスプローラ', en: 'Knowledge graph explorer' },
'graph.hubTitle': { ja: '知識グラフ', en: 'Knowledge graph' },
'graph.hubDesc': { ja: '設計書の中身 (機能・ブロック・画面項目・テーブル・列・データドメイン・EDM) を一つのグラフにして、 起点から関係をたどる。 系譜 (左から右へ、 辞書 → モデル → 物理 → 機能) と関係図 (力学モデル) を切り替え、 ノードを押すと設計書へ。 同じデータが meta/graph/graph.json で AI やグラフツールにも読める。', en: 'The whole design (functions, blocks, items, tables, columns, data domains, EDM) as one graph. Start from any node and follow its relations in a lineage view (dictionary → model → physical → function) or a force-directed view; click a node to open its document. The same data is machine-readable in meta/graph/graph.json.' },
'graph.intro': { ja: '起点を検索して選ぶと、 その周りの関係を描きます。 ノードを押すと右に詳細、 ダブルクリックで起点にします。 ホイールで拡大縮小、 ドラッグで移動。 データは meta/graph/graph.json (読み方は meta/graph/ontology.json) と同じです。', en: 'Search and pick a start node to draw its surroundings. Click a node for details, double-click to make it the start. Wheel to zoom, drag to pan. The data is the same as meta/graph/graph.json (vocabulary: meta/graph/ontology.json).' },
'graph.start': { ja: '起点', en: 'Start' },
'graph.startPh': { ja: '機能名・テーブル名 (物理名 / 論理名)・データドメイン名・ID で検索', en: 'Search by function, table (physical / logical name), data domain, ID' },
'graph.mode': { ja: '配置', en: 'Layout' },
'graph.layered': { ja: '系譜 (左から右)', en: 'Lineage (left to right)' },
'graph.force': { ja: '関係図 (力学モデル)', en: 'Relations (force-directed)' },
'graph.depth': { ja: '深さ', en: 'Depth' },
'graph.direction': { ja: '向き', en: 'Direction' },
'graph.dirBoth': { ja: '両方', en: 'Both' },
'graph.dirOut': { ja: '出る方向', en: 'Outgoing' },
'graph.dirIn': { ja: '入る方向', en: 'Incoming' },
'graph.colorBy': { ja: '色分け', en: 'Colour by' },
'graph.colorType': { ja: '種類', en: 'Type' },
'graph.colorCategory':{ ja: '業務分類', en: 'Business category' }, // No.303 (2026-10-14): 括弧の説明は外す (出所は colorHelp に)
'graph.colorProject': { ja: 'プロジェクト', en: 'Project' },
'graph.colorDept': { ja: '責任部門', en: 'Department' },
'graph.edgeLabels': { ja: '関係の名前を表示', en: 'Show relation names' },
'graph.fit': { ja: '全体を表示', en: 'Fit' },
'graph.saveSvg': { ja: 'SVG で保存', en: 'Save as SVG' },
'graph.edgeTypes': { ja: '関係の種類', en: 'Relation types' },
'graph.empty': { ja: '上の欄で起点を選んでください', en: 'Pick a start node above' },
'graph.status': { ja: 'ノード {0} / エッジ {1}', en: '{0} nodes / {1} edges' },
'graph.truncated': { ja: '(上限 {0} ノードで打ち切り。 深さや関係の種類を絞ってください)', en: '(cut at {0} nodes; narrow the depth or relation types)' },
'graph.type': { ja: '種類', en: 'Type' },
'graph.openDoc': { ja: '設計書を開く', en: 'Open the document' },
'graph.outEdges': { ja: '出る関係', en: 'Outgoing relations' },
'graph.inferred': { ja: '導出した関係', en: 'Inferred relations' },
'graph.via': { ja: '経由', en: 'via' },
'graph.viaLegend': { ja: '隠した種類を経由 (点線)', en: 'Through hidden types (dotted)' },
'graph.hiddenFmt': { ja: '非表示 {0} / 経由 {1}', en: '{0} hidden / {1} via' },
'graph.hiddenNote': { ja: '{0} は非表示', en: '{0} hidden' },
'graph.typesHelp': { ja: 'チェックを外すとその種類を隠し、そこを通る経路は点線 (経由) でつなぎます', en: 'Untick to hide the type; paths through it become dotted (via) lines' },
// ★Ver1.0.23 第 3 段 (2026-10-07): 間隔のプリセット / 箱の大きさ = 関係の数 / 末端の畳み込み
'graph.spacing': { ja: '間隔', en: 'Spacing' },
'graph.spaceAuto': { ja: '自動', en: 'Auto' },
'graph.spaceCompact': { ja: '密', en: 'Compact' },
'graph.spaceNormal': { ja: '標準', en: 'Normal' },
'graph.spaceWide': { ja: '広い', en: 'Wide' },
'graph.spaceWidest': { ja: '最広', en: 'Widest' },
'graph.sizeBy': { ja: '大きさ', en: 'Size' },
'graph.sizeNone': { ja: '一律', en: 'Uniform' },
'graph.sizeLocal': { ja: '関係の数 (表示中)', en: 'Relations (shown)' },
'graph.sizeGlobal': { ja: '関係の数 (全体)', en: 'Relations (whole graph)' },
'graph.bundle': { ja: '末端をまとめる', en: 'Bundle leaves' },
'graph.bundleLegend': { ja: 'まとめた末端 (押すと一覧、ダブルクリックで展開)', en: 'Bundled leaves (click to list, double-click to expand)' },
'graph.bundleFmt': { ja: '{0} ×{1}', en: '{0} ×{1}' },
'graph.bundled': { ja: '(末端 {0} 個を {1} 箱にまとめ)', en: '({0} leaves in {1} bundles)' },
'graph.bundleHub': { ja: 'まとめ先', en: 'Hub' },
'graph.expand': { ja: '展開', en: 'Expand' },
'graph.members': { ja: 'まとめた要素', en: 'Bundled items' },
'graph.degree': { ja: '関係の数 (全体)', en: 'Relations (whole graph)' },
'graph.inEdges': { ja: '入る関係', en: 'Incoming relations' },
'graph.center': { ja: 'これを起点にする', en: 'Make this the start' },
'graph.noHit': { ja: '該当なし', en: 'No match' },
// ★No.299〜304 (2026-10-09): 色分けの凡例 / 候補の打ち切り / 業務分類のリンク先
'graph.colorNone': { ja: '該当なし', en: 'None' },
'graph.colorMixed': { ja: '複数 (混在)', en: 'Mixed' },
'graph.colorLegend': { ja: '色の意味', en: 'Colours' },
'graph.colorHelp': { ja: '業務分類は機能から、プロジェクト / 責任部門はデータドメインから、表示中の関係をたどって周りの要素にも色を伝えます。色の意味は右の凡例に出ます', en: 'Business category spreads from functions, project / department from data domains, along the relations shown. The legend on the right lists the colours' },
'graph.moreHits': { ja: '…他 {0} 件 (語を足して絞り込んでください)', en: '… {0} more (add words to narrow down)' },
'graph.openIndex': { ja: '設計書インデックスで見る (この業務分類の機能)', en: 'Open the function index (functions in this category)' },
'graph.loadError': { ja: 'graph-data.js を読み込めませんでした (ZIP を展開したフォルダから開いてください)', en: 'Could not load graph-data.js (open the page from the extracted folder)' },
'graph.backHub': { ja: '← 設計書の入口へ', en: '← Back to the hub' },
'graph.lane.context': { ja: '文脈', en: 'Context' },
'graph.lane.dictionary': { ja: '業務データ辞書', en: 'Dictionary' },
'graph.lane.edm': { ja: 'EDM', en: 'EDM' }, // ★2026-10-12: EDM (モデル) を独立のレーンに (テスター要望)。 10-13: 8 レーンに細分化 (ユーザー指示)
'graph.lane.entity': { ja: 'EDM エンティティ', en: 'EDM entities' },
'graph.lane.attribute': { ja: 'EDM 属性', en: 'EDM attributes' },
'graph.lane.table': { ja: '物理テーブル', en: 'Physical tables' },
'graph.lane.column': { ja: '物理列', en: 'Physical columns' },
'graph.inferredStartOnly': { ja: '導出は起点からだけ', en: 'Inferred: from the start only' }, // 2026-10-13: 深さの広げ方
'graph.inferredStartOnlyHelp': { ja: '導出した関係 (破線) は起点から出る 1 本目だけに使い、 2 本目以降の広がりには使いません (例: 顧客納期を扱う機能は出るが、 その機能が扱う別のデータドメインまでは出ない)', en: 'Inferred relations (dashed) are followed only from the start node, not from deeper nodes' },
'graph.stopHubs': { ja: '文脈を通り抜けない', en: 'Stop at context' },
'graph.stopHubsHelp': { ja: 'プロジェクト・責任部門・業務分類は起点でない限り、 そこから先へ広げません (責任部門 → 他のデータドメイン のような広がりを止める)', en: 'Project / department / category nodes are not expanded unless they are the start' },
'graph.noDescend': { ja: '入れ物の中身へ広がらない', en: 'Containers: contents from the start only' }, // 2026-10-14: 第 10 段
'graph.noDescendHelp': { ja: '入れ物 (EDM ⊃ エンティティ ⊃ 属性、 機能 ⊃ ブロック ⊃ 項目、 テーブル ⊃ 列、 データドメイン ⊃ 物理属性) は、 中身から入れ物へは文脈として上がりますが、 入れ物から別の中身へは起点が入れ物のときだけ下ります (例: 商品コードから受注エンティティは出るが、 受注の他の属性は出ない)', en: 'Containers (EDM ⊃ entity ⊃ attribute, function ⊃ block ⊃ item, table ⊃ column, data domain ⊃ physical attribute) are reached upward as context, but their other contents are expanded only when the container is the start (e.g. from 商品コード the 受注 entity appears, but not its other attributes)' },
'graph.lane.function': { ja: '機能', en: 'Functions' },
'search.none': { ja: '一致する箇所はありません', en: 'No matches' },
'search.hits': { ja: '{0} 箇所 / {1} ページ (スペース区切りは AND。大小文字・全角半角は区別しません)',
en: '{0} hits in {1} pages (space-separated terms are ANDed; case and width are ignored)' },
'search.more': { ja: '先頭 {0} 箇所のみ表示しています。語を足して絞り込んでください', en: 'Showing the first {0} hits. Add terms to narrow down' },
'search.close': { ja: '閉じる (Esc)', en: 'Close (Esc)' },
'search.back': { ja: '↩ 検索結果に戻る', en: '↩ Back to results' },
'search.backClose': { ja: '「検索結果に戻る」を消す', en: 'Dismiss "Back to results"' },
// ---- 機能設計書 MD の拡充 (Ver1.0.1): 生データ / データドメイン照合 ----
'md.rawData': { ja: '生データ (DB レコード)', en: 'Raw data (DB records)' },
'md.rawDataIntro': { ja: 'TALON リポジトリにある当機能のレコードを全列そのまま列挙します (設定画面に現れない列や、ブロックに紐付かない残存行も含む)。長文の列は表に参照番号だけを置き、本文は表の下にコードブロックで示します。',
en: 'Every repository record of this function with all columns (including columns not shown on screens and orphan rows not tied to any block). Long text columns are referenced by number in the table and listed below it.' },
'md.rawLongRef': { ja: '{0}文字 → #{1}', en: '{0} chars → #{1}' },
'md.rawLongHead': { ja: '長文列の本文', en: 'Long text columns' },
'md.domainTab': { ja: 'データドメイン照合', en: 'Data domain matching' },
'md.domainTabIntro': { ja: '当機能の画面項目と業務データ辞書 (データドメイン) の照合結果です。未登録項目は辞書に登録するか、システム列なら照合除外に登録してください。',
en: 'Result of matching the screen items of this function against the business data dictionary (data domains). Register unregistered items in the dictionary, or exclude them if they are system columns.' },
'md.domainUsed': { ja: '一致したデータドメイン', en: 'Matched data domains' },
'md.domainNoneUsed': { ja: '当機能の項目でデータドメインと一致するものはありませんでした。', en: 'No items in this function matched any registered domain.' },
'md.domainAmbig': { ja: '複数ドメイン一致 (要確認)', en: 'Ambiguous domain matches (needs review)' },
'md.domainUnreg': { ja: '未登録項目 (辞書未登録)', en: 'Unregistered items (not in the dictionary)' },
'md.domainItems': { ja: '{0}項目', en: '{0} items' },
'md.blockLevelFunc': { ja: '機能全体', en: 'function-level' },
// ---- ER.md の拡充 (Ver1.0.1): er-diagram.html と同等の情報 ----
'md.erIntro': { ja: 'テーブル / 列 / 外部キーを DB 接続先別に列挙し、er-diagram.html と同じ付加情報を付けます: 分類 (RESOURCE/EVENT 等)、業務分類 (テーブルを更新する機能の分類)、EDM エンティティ、使用機能 (✏ = 更新)、各列のデータドメイン照合 (⚠ 未登録 / 照合除外)。物理名はソース DB の元 case を保持し、論理名とコメントは COMMENT ON COLUMN / Description 由来です。',
en: 'Tables, columns, and foreign keys grouped by DB connection, with the same enrichment as er-diagram.html: entity kind, business category (by the functions that write the table), EDM entity, functions using the table (✏ = write), and the data-domain match of every column (⚠ unregistered / excluded). Physical names keep the source DB casing; logical names and comments come from COMMENT ON COLUMN / Description.' },
'md.erTableList': { ja: 'テーブル一覧', en: 'Table list' },
'md.erKind': { ja: '分類', en: 'Kind' },
'md.erBg': { ja: '業務分類 (メンテ機能基準)', en: 'Business category (by writer)' },
'md.erEdm': { ja: 'EDM', en: 'EDM' },
'md.erFuncs': { ja: '使用機能', en: 'Functions' },
'md.erWrite': { ja: '更新', en: 'write' },
'md.erRead': { ja: '参照', en: 'read' },
'md.erFuncCounts': { ja: '更新 / 参照 機能数', en: 'Write / read funcs' },
'md.erColCounts': { ja: '列数 / 子FK / 親FK', en: 'Cols / FK in / FK out' },
'md.erDomain': { ja: 'データドメイン', en: 'Data domain' },
'md.erUnreg': { ja: '未登録', en: 'unregistered' },
'md.erExcl': { ja: '照合除外', en: 'excluded' },
'md.erAmbig': { ja: '複数一致', en: 'ambiguous' },
'md.erIndexes': { ja: '索引 (インデックス)', en: 'Indexes' },
'md.erLogical': { ja: '論理名', en: 'Logical name' },
'md.erComment': { ja: 'コメント (説明)', en: 'Comment' },
'md.erFkRef': { ja: 'FK 参照先', en: 'FK reference' },
'md.erWarnUnreg': { ja: 'データドメイン 未登録の物理列', en: 'Physical columns not registered in any data domain' },
'md.erWarnUnregIntro': { ja: '以下の物理列はどのデータドメインにも一致せず、照合除外にも登録されていません。データドメインに登録するか、システム列なら照合除外に登録してください。',
en: 'These physical columns match no data domain and are not on the matching-exclusion list. Register a data domain, or exclude them if they are system columns.' },
'md.erWarnAmbig': { ja: 'データドメイン不整合 (1 列が複数ドメインに一致)', en: 'Data domain inconsistencies (a column matches multiple domains)' },
'md.erWarnLint': { ja: 'スキーマ整合性チェック', en: 'Schema integrity check' },
'md.erLintPkless': { ja: '更新対象だが主キーが検出できない (更新・複写・削除が不安定になる可能性)', en: 'update target but no primary key detected (update / copy / delete may be unstable)' },
'md.erNoWarn': { ja: '所見なし', en: 'no findings' }
};
TFC.t = function (key, lang) {
var entry = _labels[key];
if (!entry) return key;
var l = (lang === 'en') ? 'en' : 'ja';
return entry[l] != null ? entry[l] : (entry.ja != null ? entry.ja : key);
};
// ============================================================
// 機能下部バー (bottombar) ボタンカテゴリの表示順
// ============================================================
// TALON 実画面の慣行に従う左→右の順序を 1 配列にまとめる。
// 順序を変えたいときは この配列だけを変えれば全機能に波及する。
// 出力系 (PDF サイズ → PDF → Excel → 帳票 → ファイル → CSV出力)
// → 取込系 (CSV ドロップゾーン → Excel 更新 → CSV登録)
// → 通信系 (BAT 処理呼出 → AJAX 非同期)
// → 確定 (右側固定)
//
// 各キーは update-before.server.js の renderTlnBottombar 内のエミッタと対応する。
// 不明なキーは無視される (= レンダラに対応エミッタが無いカテゴリは安全に skip)。
TFC.BOTTOMBAR_CATEGORY_ORDER = [
'PDF_SIZE',
'PDF_BTN',
'EXCEL_BTN',
'BUTTON_REPORT',
'BUTTON_FILEIO',
'CSV_OUT_BUTTON',
'CSV_LOAD_DROPZONE',
'BUTTON_EXCEL_UPDATE',
'CSV_LOAD_BUTTON',
'BUTTON_BAT',
'BUTTON_AJAX'
];
// メッセージ内の {0}, {1} を args[0], args[1] で置換
TFC.tf = function (key, lang, args) {
var s = TFC.t(key, lang);
if (args && args.length) {
for (var i = 0; i < args.length; i++) {
s = s.split('{' + i + '}').join(args[i] != null ? String(args[i]) : '');
}
}
return s;
};
// ============================================================
// 言語・ラベル
// ============================================================
TFC.toLocale = function (lang) {
if (!lang) return Locale.JAPANESE;
var s = String(lang);
if (s.indexOf('_') > 0) {
var p = s.split('_');
return new Locale(p[0], p[1]);
}
if (s === 'ja') return Locale.JAPANESE;
if (s === 'en') return Locale.ENGLISH;
return new Locale(s);
};
// 5系 TALON は general_ja_JP.properties / general_en_US.properties 等、
// 国コード付きの ResourceBundle ファイル名を使用しているため、
// 6系のロケール (ja / en) で取得失敗した際の互換 fallback を提供する
TFC.toLocaleWithCountry = function (lang) {
var m = { ja: ['ja','JP'], en: ['en','US'], zh: ['zh','CN'], ko: ['ko','KR'] };
var s = String(lang || 'ja');
var p = m[s];
return p ? new Locale(p[0], p[1]) : null;
};
var _bundleCache = {};
// ResourceBundle 'general' は TALON 標準の翻訳リソース。
// 6系 (Payara 6.x / JDK 11): デフォルトの ResourceBundle.getBundle で成功。
// 5系 (Payara 5.2): Nashorn の eval クラスローダが WEB-INF/classes を見られず
// MissingResourceException になることがある。複数のクラスローダソースを順に試す:
// (1) Thread.currentThread().getContextClassLoader()
// (2) jp.talon.common.message.MessageManager のクラスローダ (TALON 本体クラスから取得)
// (3) ResourceBundle 自身のクラスローダ
// 各 classloader に対しさらに locale を (a) 国コード付き ja_JP / (b) 言語のみ ja で試行。
// 全て失敗した場合は null を返し、TFC.lbl は fallback / key で動作継続。
function _tryGetBundle(locale, classLoader) {
try {
return classLoader
? ResourceBundle.getBundle('general', locale, classLoader)
: ResourceBundle.getBundle('general', locale);
} catch (e) {
return null;
}
}
function _classLoaderSources() {
var srcs = [];
// (1) ContextClassLoader
try { srcs.push(Java.type('java.lang.Thread').currentThread().getContextClassLoader()); } catch (e) {}
// (2) TALON 本体クラスのクラスローダ (WEB-INF/classes 配下を読める想定)
var talonClasses = ['jp.talon.common.message.MessageManager',
'jp.talon.application.general.free.ap.process.ExecuteProcess'];
for (var i = 0; i < talonClasses.length; i++) {
try {
var T = Java.type(talonClasses[i]);
srcs.push(T.class.getClassLoader());
} catch (e) {}
}
// (3) ResourceBundle 自身のクラスローダ (フォールバック)
try { srcs.push(ResourceBundle.class.getClassLoader()); } catch (e) {}
// null や重複を除去
var seen = [], out = [];
for (var j = 0; j < srcs.length; j++) {
var cl = srcs[j];
if (!cl) continue;
if (seen.indexOf(cl) >= 0) continue;
seen.push(cl); out.push(cl);
}
return out;
}
TFC.getLabelBundle = function (lang) {
var key = lang || 'ja';
if (key in _bundleCache) return _bundleCache[key];
var loc = TFC.toLocale(key);
var locFb = TFC.toLocaleWithCountry(key);
var cls = _classLoaderSources();
var b = null;
// 各 classloader × 各 locale を試行
for (var ci = 0; !b && ci < cls.length; ci++) {
if (locFb) b = _tryGetBundle(locFb, cls[ci]);
if (!b) b = _tryGetBundle(loc, cls[ci]);
}
// 最後に引数なしも試行
if (!b && locFb) b = _tryGetBundle(locFb, null);
if (!b) b = _tryGetBundle(loc, null);
if (!b) {
try { TALON.getLogger().writeInfo('[TFC] ResourceBundle "general" 取得失敗 — fallback 文字列を使用 (key=' + key + ', tried ' + cls.length + ' classloaders)'); } catch (ignore) {}
} else {
try { TALON.getLogger().writeInfo('[TFC] ResourceBundle "general" 取得成功 (key=' + key + ')'); } catch (ignore) {}
}
_bundleCache[key] = b;
return b;
};
TFC.lbl = function (bundle, key, fallback) {
if (!bundle) return fallback != null ? fallback : key;
try {
return String(bundle.getString(key));
} catch (e) {
return fallback != null ? fallback : key;
}
};
// ============================================================
// エスケープ
// ============================================================
TFC.escapeHtml = function (s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
TFC.escapeAttr = function (s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
TFC.escapeMd = function (s) {
if (s == null) return '';
// テーブル区切り (|)、 コード (`)、 強調 (*)、 エスケープ自身 (\\) だけをエスケープする。
// _ ( ) [ ] # + - ! { } > は CommonMark ではテキスト中 (表のセル / 行の途中) で意味を持たず、
// 単語内の _ も強調にならない。 旧実装はこれらも \\ 付きにしていたため、 物理名や機能ID が
// `XDMF\\_BF100\\_0` のようになり AI / 検索の完全一致を壊していた (Ver1.0.1 で緩和)。
return String(s).replace(/([\\`*|])/g, '\\$1');
};
TFC.formatSql = function (s) {
if (s == null) return '';
return String(s).replace(/\r\n/g, '\n').replace(/\t/g, ' ').replace(/\n+$/, '');
};
// ============================================================
// APP_KBN ラベル ([TALON-DB設定マスタ.md] 出典)
// ============================================================
var APP_KBN_MAP = {
ja: { STD: '固定検索条件', FREE: 'フリー検索条件', SUB: '検索子画面', BAT: '検索ボタン無し' },
en: { STD: 'Fixed search condition', FREE: 'Free search condition', SUB: 'Sub search screen', BAT: 'No search button' }
};
TFC.appKbnLabel = function (appKbn, lang) {
var l = (lang && APP_KBN_MAP[lang]) ? lang : 'ja';
var m = APP_KBN_MAP[l];
return (m && m[appKbn]) || appKbn || '';
};
// ============================================================
// 項目情報の値マッピング
// ============================================================
// 出典: 公式マスタ #00316-#00321 (TALON_設定カタログ.md §12 / DB設定マスタ.csv)
// - 空/0: テキスト入力 (デフォルト)
// - 1: リストボックス
// - 2: 検索条件ラジオ/結果リスト
// - 3: 検索条件チェック/結果リスト
// - 4: ラジオボタン
// - 5: チェックボックス
// - 6: HIDDEN (非表示) — isHiddenItem() でこの値を検出
var COMPONENT_MAP = {
ja: {
'': 'テキスト入力', '0': 'テキスト入力',
'1': 'リストボックス',
'2': '検索条件ラジオ/結果リスト',
'3': '検索条件チェック/結果リスト',
'4': 'ラジオボタン',
'5': 'チェックボックス',
'6': 'HIDDEN (非表示)'
},
en: {
'': 'Text input', '0': 'Text input',
'1': 'List box',
'2': 'Search radio / result list',
'3': 'Search check / result list',
'4': 'Radio button',
'5': 'Checkbox',
'6': 'HIDDEN'
}
};
TFC.componentLabel = function (val, lang) {
var v = val == null ? '' : String(val);
var m = COMPONENT_MAP[lang === 'en' ? 'en' : 'ja'];
return (m && m[v]) || v;
};
// 出典: 公式マスタ #01441 + カタログ §12 DATA_TYPE 一覧
// - VARCHAR2: Java String
// - NUMBER: Java BigDecimal
// - DATE: Java java.sql.Date
// - DATETIME: Java Timestamp (※TIMESTAMP はエイリアスとして互換維持)
// - CLOB: Java String(CLOB)
var DATA_TYPE_MAP = {
ja: {
'VARCHAR2': '文字列 (VARCHAR2)',
'NUMBER': '数値 (NUMBER)',
'DATE': '日付 (DATE)',
'DATETIME': '日時 (DATETIME)',
'TIMESTAMP': '日時 (DATETIME)', // 互換エイリアス
'CLOB': 'CLOB (長文テキスト)'
},
en: {
'VARCHAR2': 'String (VARCHAR2)',
'NUMBER': 'Number (NUMBER)',
'DATE': 'Date (DATE)',
'DATETIME': 'Datetime (DATETIME)',
'TIMESTAMP': 'Datetime (DATETIME)',
'CLOB': 'CLOB (Large text)'
}
};
TFC.dataTypeLabel = function (val, lang) {
var v = val == null ? '' : String(val).toUpperCase();
var m = DATA_TYPE_MAP[lang === 'en' ? 'en' : 'ja'];
return (m && m[v]) || v;
};
// AUTO-GENERATED by tools/build_value_enum_js.py
// Source: talon-docs/_TALON仕様分析/DB設定/DB設定マスタ.csv (COL == DB_VALUE entries)
// 編集禁止 — 再生成するには `python tools/build_value_enum_js.py`
// 構造: VALUE_ENUMS[<FUNC_KBN>][<DB値>] = <表示名>
var VALUE_ENUMS = {
'ALL_REG_FLG': {
'1': 'ON',
},
'ALL_SELECT_CHECK': {
'1': 'ON',
},
'BACK_BUTTON_HDN_FLG': {
'1': 'ON',
},
'BACK_COLOR': {
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'MACRO': 'マクロ',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'REG': '正規表現',
'SUFFIX': 'SUFFIX',
},
'BACK_COLOR_TR_KBN_': {
'MACRO': 'マクロ',
},
'BARCODE_FORMAT': {
'15%': '15%',
'25%': '25%',
'30%': '30%',
'7%': '7%',
'CODABAR': 'CODABAR',
'CODE_128': 'CODE 128',
'CODE_39': 'CODE 39',
'CODE_93': 'CODE 93',
'DATA_MATRIX': 'DATA MATRIX',
'EAN_13': 'EAN 13',
'EAN_8': 'EAN 8',
'ITF': 'ITF',
'QR': 'QR',
'UPC_A': 'UPC A',
'UPC_E': 'UPC E',
},
'BLOCK': {
'0': 'ON',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'BLOCK_NAME_HDN_FLG': {
'1': 'ON',
},
'BUTTON_AJAX': {
'1': 'ON',
'INIT': '画面起動直後から',
'SEARCH': '初回検索ボタン押下後',
},
'BUTTON_BAT': {
'0': 'OFF',
'1': 'ON',
},
'BUTTON_BAT_': {
'TLN_LOGIN_BUMON': 'ログイン部門',
'TLN_LOGIN_USER': 'ログインID',
},
'BUTTON_NEXT': {
'0': '照会',
'1': 'ON',
'BTN_BTM': 'ボタンの下',
'BTN_R': 'ボタンの右',
'WIN_C_BTM': 'Window中央下',
'WIN_C_MDL': 'Window中央',
'WIN_C_TOP': 'Window中央上',
'WIN_L_BTM': 'Window左下',
'WIN_L_MDL': 'Window左中央',
'WIN_L_TOP': 'Window左上',
'WIN_R_BTM': 'Window右下',
'WIN_R_MDL': 'Window右中央',
'WIN_R_TOP': 'Window右上',
},
'BUTTON_NEXT_': {
'1': 'ON',
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'BETWEEN': 'BETWEEN',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'SUFFIX': 'SUFFIX',
'TLN_LOGIN_BUMON': 'ログイン部門',
'TLN_LOGIN_USER': 'ログインID',
'day': 'day',
'dayGridMonth': 'month',
'halfYear': 'halfYear',
'hour': 'hour',
'minute': 'minute',
'month': 'month',
'quarterly': 'quarterly',
'second': 'second',
'timeGridDay': 'day',
'timeGridWeek': 'week',
'week': 'week',
'year': 'year',
},
'BUTTON_REPORT': {
'1': 'ON',
'2': 'ボタンと確定後',
'CLI_DIALOG': 'プリンタダイアログ表示',
'CLI_PRINTER': '通常使うプリンタに直接出力',
'DIALOG': 'プリンタダイアログ表示',
'EXCEL': 'EXCEL',
'PDF': 'PDF',
'PREVIEW': 'プレビュー印刷',
'PRINT': '通常使うプリンタに直接出力',
'PRINTER': 'サーバプリンタへ直接印刷',
'WORD': 'WORD',
},
'CAMMA_OFF': {
'1': 'ON',
},
'CHART': {
'0': '照会',
'1': 'ON',
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'BETWEEN': 'BETWEEN',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'SUFFIX': 'SUFFIX',
'TLN_LOGIN_BUMON': 'ログイン部門',
'TLN_LOGIN_USER': 'ログインID',
'WIN_C_BTM': 'Window中央下',
'WIN_C_MDL': 'Window中央',
'WIN_C_TOP': 'Window中央上',
'WIN_L_BTM': 'Window左下',
'WIN_L_MDL': 'Window左中央',
'WIN_L_TOP': 'Window左上',
'WIN_R_BTM': 'Window右下',
'WIN_R_MDL': 'Window右中央',
'WIN_R_TOP': 'Window右上',
'area': '折れ線エリア',
'area_spline': '曲線エリア',
'area_step': '階段エリア',
'bar': '棒',
'bottom': '下',
'day': 'day',
'dayGridMonth': 'month',
'donut': 'ドーナツ',
'halfYear': 'halfYear',
'hour': 'hour',
'inner-bottom': '枠内下',
'inner-center': '枠内中央',
'inner-left': '枠内左',
'inner-middle': '枠内中央',
'inner-right': '枠内右',
'inner-top': '枠内上',
'line': '折れ線',
'minute': 'minute',
'month': 'month',
'outer-bottom': '枠外下',
'outer-center': '枠外中央',
'outer-left': '枠外左',
'outer-middle': '枠外中央',
'outer-right': '枠外右',
'outer-top': '枠外上',
'pie': '円',
'quarterly': 'quarterly',
'ratio': '比率',
'right': '右',
'scatter': '散布図',
'second': 'second',
'spline': '曲線',
'step': '階段',
'timeGridDay': 'day',
'timeGridWeek': 'week',
'value': '値',
'week': 'week',
'year': 'year',
},
'CHART_MARK': {
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'MACRO': 'マクロ',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'REG': '正規表現',
'SUFFIX': 'SUFFIX',
},
'CLEAR_BUTTON_HDN_FLG': {
'1': 'ON',
},
'COL_BUTTON_HDN_FLG': {
'1': 'ON',
},
'CONDITION': {
'0': 'ON',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'CONDITION_AREA': {
'1': '領域削除',
},
'COND_SAVE_HDN_FLG': {
'1': 'ON',
},
'CR_FLG_SEARCH': {
'1': 'ON',
},
'CSV_LOAD_BUTTON': {
'1': 'ON',
},
'CSV_LOAD_BUTTON_FILE': {
'1': 'ON',
'FIX': '固定長',
'VAR': '可変長',
},
'CSV_LOAD_BUTTON_OPTION': {
'"': '”',
'\'': '\'',
'1': 'ON',
'CAMMA': 'カンマ',
'EUC_JP': 'EUC',
'ISO-2022-JP': 'JISコード',
'ISO-8859-1': 'ASCII',
'NULL': 'なし',
'Shift_JIS': 'Shift_JIS',
'TAB': 'タブ',
'UTF-8': 'UTF-8',
},
'CSV_OUT_BUTTON': {
'1': 'ON',
},
'CSV_OUT_BUTTON_FILE': {
'FIX': '固定長',
'VAR': '可変長',
},
'CSV_OUT_BUTTON_OPTION': {
'"': '”',
'\'': '\'',
'1': 'ON',
'CAMMA': 'カンマ',
'EUC_JP': 'EUC',
'ISO-2022-JP': 'JISコード',
'ISO-8859-1': 'ASCII',
'NULL': 'なし',
'Shift_JIS': 'Shift_JIS',
'TAB': 'タブ',
'UTF-8': 'UTF-8',
'\\n': 'Lf',
'\\r': 'Cr',
'\\r\\n': 'CrLf',
},
'DELETE_FLG': {
'1': 'ON',
},
'DISP_POS': {
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'DRILL_DOWN': {
'1': 'ON',
},
'EXCELUPDATE_BTN_DISABLED_FLG': {
'1': 'ON',
},
'EXCELUPDATE_BUTTON_HDN_FLG': {
'1': 'ON',
},
'EXCEL_BUTTON_HDN_FLG': {
'1': 'ON',
},
'EXCLUSIVE_CONTROL_FLG': {
'1': 'ON',
},
'EXECUTE_BTN_HDN_FLG': {
'1': 'ON',
},
'EXE_DISP_INIT_FLG': {
'0': '初期化しない',
'1': '初期化する',
},
'EXE_DISP_TARGET_ONLY_FLG': {
'1': 'ON',
},
'EXE_TARGET_ONLY_FLG_NO_SEARCH': {
'1': 'ON',
},
'FIX_FORMULA': {
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'BETWEEN': 'BETWEEN',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'SUFFIX': 'SUFFIX',
},
'FLAT_TEXT': {
'1': 'ON',
},
'FORE_COLOR': {
'1': 'ON',
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'MACRO': 'マクロ',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'REG': '正規表現',
'SUFFIX': 'SUFFIX',
},
'FORE_COLOR_TR_KBN_': {
'MACRO': 'マクロ',
},
'FUNC_BUTTON_AREA_BTM': {
'0': 'ON',
'1': '領域削除',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'FUNC_BUTTON_AREA_HEAD': {
'0': 'ON',
'1': '領域削除',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'FUNC_BUTTON_AREA_TOP': {
'0': 'ON',
'1': '領域削除',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'FUNC_TOP_AREA': {
'0': 'ON',
'1': '領域削除',
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'GANTT_DAY_GRID_INIT_VAL': {
'hour': 'hour',
'minute': 'minute',
},
'GANTT_HALF_YEAR_GRID_INIT_VAL': {
'month': 'month',
'week': 'week',
},
'GANTT_HOUR_GRID_INIT_VAL': {
'hour': 'hour',
'minute': 'minute',
},
'GANTT_MONTH_GRID_INIT_VAL': {
'day': 'day',
'hour': 'hour',
},
'GANTT_ONE_YEAR_GRID_INIT_VAL': {
'month': 'month',
'week': 'week',
},
'GANTT_QTR_YEAR_GRID_INIT_VAL': {
'month': 'month',
'week': 'week',
},
'GANTT_WEEK_GRID_INIT_VAL': {
'day': 'day',
'hour': 'hour',
},
'GANTT_YEARS_GRID_INIT_VAL': {
'month': 'month',
'year': 'year',
},
'HDN_LIST_SORT': {
'1': 'ON',
},
'HDN_PAGER_FLG': {
'1': 'ON',
},
'INIT_VALUE': {
'TLN_LOGIN_BUMON': 'ログイン部門',
'TLN_LOGIN_USER': 'ログインID',
'TLN_SYSDATE': 'システム日付',
'TLN_SYSDATE_FST': 'システム月初',
'TLN_SYSDATE_LST': 'システム月末',
},
'INPUT_CONDITION': {
'1': 'ON',
},
'INSERT_FLG': {
'1': 'ON',
},
'IS_ALL_DAY_CHECK_ON': {
'1': 'OFF',
},
'IS_BAR_MOUSE_ALLOW_MOVING': {
'OFF': 'OFF',
},
'IS_BAR_MOUSE_ALLOW_RESIZING': {
'OFF': 'OFF',
},
'IS_BAR_UPDATE_CONFIRM': {
'1': 'ON',
},
'IS_CLOSE_SWITCH': {
'1': 'ON',
},
'IS_CONDITION_TITLE_OFF': {
'1': 'ON',
},
'IS_DB_NOT_REGIST': {
'1': 'ON',
},
'IS_EXECUTE_CONFIRM': {
'1': 'ON',
},
'IS_EXECUTE_MESSAGE_HIDDEN': {
'1': 'ON',
},
'IS_EXE_AUTH': {
'ON': 'ON',
},
'IS_FIT_EVENT_BAR_MAX_WIDTH': {
'1': 'ON',
},
'IS_GANTT_DISP_DAY_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_HALF_YEAR_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_HOUR_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_MONTH_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_QUARTERLY_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_WEEK_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_YEARS_BTN': {
'1': 'OFF',
},
'IS_GANTT_DISP_YEAR_BTN': {
'1': 'OFF',
},
'IS_GRID_SNAP_OFF': {
'1': 'ON',
},
'IS_LIST_FIXED': {
'ON': 'ON',
},
'IS_LIST_ROW_SELECT': {
'1': 'ON',
},
'IS_NOT_WIN_RESIZE': {
'1': 'ON',
},
'IS_ON_RELOAD_ORIGIN_WIN_SIZE': {
'1': 'ON',
},
'IS_SCALE_HIDDEN_DAY': {
'1': 'OFF',
},
'IS_SCALE_HIDDEN_MONTH': {
'1': 'OFF',
},
'IS_SCALE_HIDDEN_WEEK': {
'1': 'OFF',
},
'IS_SCHEDULE_UIWAIT_LOCK': {
'1': 'ON',
},
'IS_SEARCH_NOTFOUND_MSG_HDN': {
'1': 'ON',
},
'IS_ST_ED_TOOLTIP_HIDDEN': {
'1': 'ON',
},
'IS_TASK_GROUING_DISP': {
'1': 'ON',
},
'IS_USE_SEARCH_RESULT_MAIL': {
'1': 'ON',
},
'IS_USE_SEARCH_RESULT_REPORT': {
'1': 'ON',
},
'IS_VERTICAL_LAYOUT': {
'1': 'ON',
},
'IS_WIN_OPENER_CLOSED': {
'OFF': 'OFF',
},
'KEY_COL_BLOCK': {
'0': '表示しない',
'1': '表示する',
},
'LOOK_UP': {
'WAIT_LOCK': 'ON',
},
'MASTER_CHECK': {
'1': 'ON',
},
'MATCH_PATTERN': {
'1': 'ON',
'ALL_MATCH': 'エラー条件',
'NULL': '許可条件 ※この設定は現在できない',
},
'OPEN_WINDOW_MODE': {
'NEW_WIN': '常に別Window',
'NORMAL': '別Window (既存あれば上書き)',
'NORMAL_DIALOG': '別Window (既存あれば警告)',
'OVER_WRITE': '上書き',
'OVER_WRITE_SEARCH': '上書き+親再検索',
},
'OPTION_LIST_SEARCH': {
'1': 'ON',
'WAIT_LOCK': 'ON',
},
'OTHER_FUNC': {
'1': 'ON',
'DELETE': '削除',
'INSERT': '登録',
'MERGE': '登録/更新',
'UPDATE': '更新',
},
// CHART 系 値辞書
'CHART_FUNC_INFO': {
'bar': '棒グラフ',
'line': '折れ線',
'pie': '円グラフ',
'donut': 'ドーナツ',
'area': '面グラフ',
'scatter': '散布図',
'spline': 'スプライン',
'step': '階段グラフ',
'area_spline': '面 (スプライン)',
'area_step': '面 (階段)',
},
'CHART_BASE': {
'1': 'ON',
},
'CHART_LEGEND_BASE': {
'1': 'ON',
'bottom': '下',
'right': '右',
'top': '上',
'left': '左',
},
'CHART_AXIS_X_LABEL_BASE': {
'inner-right': '内側-右',
'inner-center': '内側-中央',
'inner-left': '内側-左',
'outer-right': '外側-右',
'outer-center': '外側-中央',
'outer-left': '外側-左',
},
'CHART_AXIS_Y_LABEL_BASE': {
'inner-top': '内側-上',
'inner-middle': '内側-中央',
'inner-bottom': '内側-下',
'outer-top': '外側-上',
'outer-middle': '外側-中央',
'outer-bottom': '外側-下',
},
'CHART_AXIS_Y_R_LABEL_BASE': {
'inner-top': '内側-上',
'inner-middle': '内側-中央',
'inner-bottom': '内側-下',
'outer-top': '外側-上',
'outer-middle': '外側-中央',
'outer-bottom': '外側-下',
},
'PDF_BUTTON_HDN_FLG': {
'1': 'ON',
},
'REGIST_VALUE': {
'<': '<',
'<=': '<=',
'<>': '<>',
'=': '=',
'>': '>',
'>=': '>=',
'IN': 'IN',
'INFIX': 'INFIX',
'IS NOT NULL': 'IS NOT NULL',
'IS NULL': 'IS NULL',
'LIKE': 'LIKE',
'MACRO': 'マクロ',
'NOT IN': 'NOT IN',
'NOT LIKE': 'NOT LIKE',
'PREFIX': 'PREFIX',
'REG': '正規表現',
'SUFFIX': 'SUFFIX',
},
'REQUIRED_SEARCH': {
'1': 'ON',
},
'RESULT_AREA': {
'C': '中央',
'C_BTM': '下中央',
'C_MDL': '中間中央',
'C_TOP': '上中央',
'L': '左',
'L_BTM': '下左',
'L_MDL': '中間左',
'L_TOP': '上左',
'R': '右',
'R_BTM': '下右',
'R_MDL': '中間右',
'R_TOP': '上右',
},
'SCHEDULE_INIT_SCALE': {
'day': 'ON',
'dayGridMonth': '月',
'halfYear': 'ON',
'hour': 'ON',
'month': 'ON',
'quarterly': 'ON',
'timeGridDay': '日',
'timeGridWeek': '週',
'week': 'ON',
'year': 'ON',
'years': 'ON',
},
'SCHEDULE_START_WEEK': {
'0': 'Sun.',
'1': 'Mon.',
'2': 'Tue.',
'3': 'Wed.',
'4': 'Thu.',
'5': 'Fri.',
'6': 'Sat.',
},
'SEARCH_BUTTON_HDN_FLG': {
'1': 'ON',
},
'SEARCH_FUNC_ID': {
'BTN_BTM': 'ボタンの下',
'BTN_R': 'ボタンの右',
'WIN_C_BTM': 'Window中央下',
'WIN_C_MDL': 'Window中央',
'WIN_C_TOP': 'Window中央上',
'WIN_L_BTM': 'Window左下',
'WIN_L_MDL': 'Window左中央',
'WIN_L_TOP': 'Window左上',
'WIN_R_BTM': 'Window右下',
'WIN_R_MDL': 'Window右中央',
'WIN_R_TOP': 'Window右上',
},
'SEARCH_METHOD': {
'=': '=',
'BETWEEN': 'BETWEEN',
'IN': 'IN',
'INFIX': 'INFIX',
'NOT IN': 'NOT IN',
'PREFIX': 'PREFIX',
'SUFFIX': 'SUFFIX',
},
'SEND_MAIL': {
'1': 'ON',
},
'SERIAL_NUMBER_VAL': {
'1': 'ON',
},
'STD_EXCEL_EXT': {
'xls': 'xls',
'xlsx': 'xlsx',
},
'SUB_BTN_HDN': {
'1': 'ON',
},
'SUB_SEARCH': {
'INIT_SEARCH': 'ON',
},
'SUGGEST': {
'1': 'ON',
'INIT_SEARCH': 'ON',
'SKIP_INIT_SEARCH': 'OFF',
'WAIT_LOCK': 'ON',
},
'TABLE_LAYOUT': {
'1': 'ON',
},
'TABLE_TITLE_LAYOUT': {
'1': 'ON',
},
'TATE_CHECK': {
'1': 'ON',
},
'THUMBNAIL_SIZE': {
'1': 'ON',
},
'UPDATE_FLG': {
'1': 'ON',
},
'VIEW_BUTTON_HDN_FLG': {
'1': 'ON',
},
'WIN_POS': {
'BTN_BTM': 'ボタンの下',
'BTN_R': 'ボタンの右',
'WIN_C_BTM': 'Window中央下',
'WIN_C_MDL': 'Window中央',
'WIN_C_TOP': 'Window中央上',
'WIN_L_BTM': 'Window左下',
'WIN_L_MDL': 'Window左中央',
'WIN_L_TOP': 'Window左上',
'WIN_R_BTM': 'Window右下',
'WIN_R_MDL': 'Window右中央',
'WIN_R_TOP': 'Window右上',
},
'ZERO_SPLIT': {
'1': 'ON',
},
};
TFC.VALUE_ENUMS = VALUE_ENUMS;
TFC.flgLabel = function (val) {
var v = val == null ? '' : String(val);
if (v === '1') return '○';
if (v === '0' || v === '') return '';
return v;
};
// EN 翻訳 (主要エニュメレーションのみ)。VALUE_ENUMS は DB設定マスタ.csv が JA 起源のため
// ここで手動 EN 訳を提供。未登録キーは EN モード時に raw コード値だけを返す。
TFC.VALUE_ENUMS_EN = {
'OPEN_WINDOW_MODE': {
'NORMAL': 'New window (overwrite if existing)',
'NORMAL_DIALOG': 'New window (warn if existing)',
'NEW_WIN': 'Always new window',
'OVER_WRITE': 'Overwrite current',
'OVER_WRITE_SEARCH': 'Overwrite + parent re-search'
},
'WIN_POS': {
'BTN_BTM': 'Below button',
'BTN_R': 'Right of button',
'WIN_C_TOP': 'Window center top',
'WIN_C_MDL': 'Window center middle',
'WIN_C_BTM': 'Window center bottom',
'WIN_R_TOP': 'Window right top',
'WIN_R_MDL': 'Window right middle',
'WIN_R_BTM': 'Window right bottom',
'WIN_L_TOP': 'Window left top',
'WIN_L_MDL': 'Window left middle',
'WIN_L_BTM': 'Window left bottom'
},
'KEY_COL_BLOCK': {
'1': 'Show key items in block',
'0': 'Hide key items in block'
},
'EXE_DISP_INIT_FLG': {
'0': 'Do not reset',
'1': 'Reset to initial'
}
};
// FUNC_KBN ごとの DB 値 → 表示名 解決 (TFC.VALUE_ENUMS / VALUE_ENUMS_EN 参照)。
// OPEN_WINDOW_MODE 'NORMAL_DIALOG' → '別Window (既存あれば警告) [NORMAL_DIALOG]' (JA)
// → 'New window (warn if existing) [NORMAL_DIALOG]' (EN)
// 未登録は元の値をそのまま返す (EN モードで JA 説明を出さないよう注意)。
TFC.valueLabel = function (funcKbn, val, lang) {
var v = val == null ? '' : String(val);
if (v === '') return '';
// EN モード: 先に EN 辞書を引く。未登録なら JA 辞書値が ON/OFF 系なら共通翻訳、 それ以外は raw。
if (lang === 'en') {
var enDict = (TFC.VALUE_ENUMS_EN || {})[funcKbn];
if (enDict && enDict[v]) {
return (enDict[v] === v) ? v : (enDict[v] + ' [' + v + ']');
}
// JA 辞書が 'ON'/'OFF'/'表示'/'非表示' といった bool 系を返す場合は EN 共通辞書で翻訳
// (VALUE_ENUMS_EN を全 FUNC_KBN 分用意するのは現実的でないため、 共通 fallback)
var jaDictE = (TFC.VALUE_ENUMS || {})[funcKbn];
if (jaDictE && jaDictE[v]) {
var commonEn = { 'ON': 'ON', 'OFF': 'OFF', '表示': 'Shown', '非表示': 'Hidden',
'上': 'Top', '下': 'Bottom', '左': 'Left', '右': 'Right',
'中央': 'Middle' };
var jaV = jaDictE[v];
if (commonEn[jaV] != null) {
return (commonEn[jaV] === v) ? v : (commonEn[jaV] + ' [' + v + ']');
}
}
return v; // EN 翻訳なし → コード値のみ
}
// JA モード: VALUE_ENUMS (JA 辞書) を使用
var dict = (TFC.VALUE_ENUMS || {})[funcKbn];
if (!dict) return v;
var disp = dict[v];
if (disp == null) return v;
if (disp === v) return v;
return disp + ' [' + v + ']';
};
// FUNC_KBN ラベルのみ取得 (コード "(...)" 付加なし) — 別列でコードを表示するときに使う
TFC.fkLabelOnly = function (funcKbn, lang) {
var info = TFC.funcKbnInfo ? TFC.funcKbnInfo(funcKbn) : null;
if (!info) return funcKbn || '';
if (lang === 'en' && info.labelEn) return info.labelEn;
return info.labelJa || (funcKbn || '');
};
// ============================================================
// FUNC_KBN 辞書 (Phase 3: 全208項目, TALON-DB設定マスタ.md から自動生成)
// 生成スクリプト: AI開発/scripts/build_func_kbn_dict.py
//
// section: 'app-application' | 'app-report' | 'app-othernext' | 'app-ajax'
// | 'block-item' | 'block-detail' | 'block-detail-cal'
// | 'block-report' | 'block-proc' | 'block-othernext'
// | 'block-fileio' | 'block-otherfunc' | 'block-other'
// | 'block-chart-general' | 'block-chart-x' | 'block-chart-y'
// | 'block-chart-y2' | 'block-chart-series'
// | 'free-layout' | 'auth-menu' | 'other'
// ============================================================
var FUNC_KBN_DICT = {
'KEY_COL_BLOCK': { section: 'app-application', labelJa: '機能タイプ', labelEn: 'Function type', table: 'TLN_M_GENERAL_APP' },
'OPEN_WINDOW_MODE': { section: 'app-application', labelJa: '起動Window状態', labelEn: 'Initial window state', table: 'TLN_M_GENERAL_APP' },
'WIN_H': { section: 'app-application', labelJa: 'Window高さ', labelEn: 'Window height', table: 'TLN_M_GENERAL_APP' },
'WIN_W': { section: 'app-application', labelJa: 'Window幅', labelEn: 'Window width', table: 'TLN_M_GENERAL_APP' },
'WIN_POS_X': { section: 'app-application', labelJa: '表示位置 横', labelEn: 'Position X', table: 'TLN_M_GENERAL_APP' },
'WIN_POS_Y': { section: 'app-application', labelJa: '表示位置 縦', labelEn: 'Position Y', table: 'TLN_M_GENERAL_APP' },
'WIN_POS': { section: 'app-application', labelJa: '表示位置', labelEn: 'Display position', table: 'TLN_M_GENERAL_APP' },
'IS_NOT_WIN_RESIZE': { section: 'app-application', labelJa: 'Windowサイズ変更不可', labelEn: 'Window resize disabled', table: 'TLN_M_GENERAL_APP' },
'IS_ON_RELOAD_ORIGIN_WIN_SIZE': { section: 'app-application', labelJa: '再描画時、設定したWindow位置サイズに戻す', labelEn: 'Restore window pos/size on redraw', table: 'TLN_M_GENERAL_APP' },
'IS_WIN_OPENER_CLOSED': { section: 'app-application', labelJa: 'Window終了オプション', labelEn: 'Window close option', table: 'TLN_M_GENERAL_APP' },
'TAB_MENU_NAME': { section: 'app-application', labelJa: 'ブロック', labelEn: 'Block', table: 'TLN_M_GENERAL_APP' },
'CHART': { section: 'app-application', labelJa: 'ブロック', labelEn: 'Block', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CONDTN_CNT': { section: 'app-application', labelJa: '検索条件項目数', labelEn: 'Search condition count', table: 'TLN_M_GENERAL_APP' },
'COND_SAVE_HDN_FLG': { section: 'app-application', labelJa: '検索条件保存', labelEn: 'Save search conditions', table: 'TLN_M_GENERAL_APP' },
'IS_CONDITION_TITLE_OFF': { section: 'app-application', labelJa: '検索条件タイトル', labelEn: 'Search condition title', table: 'TLN_M_GENERAL_APP' },
'BACK_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'CLEAR_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'PDF_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'EXCEL_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'SEARCH_BUTTON_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_HDN_FLG': { section: 'app-application', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_CND': { section: 'app-application', labelJa: '確定ボタン', labelEn: 'Confirm button', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_BTN_NAME_DISP_FORMULA': { section: 'app-application', labelJa: '確定ボタン', labelEn: 'Confirm button', table: 'TLN_M_GENERAL_APP' },
'EXECUTE_MESSAGE': { section: 'app-application', labelJa: '確定終了メッセージ', labelEn: 'Confirm result message', table: 'TLN_M_GENERAL_APP' },
'IS_EXECUTE_MESSAGE_HIDDEN': { section: 'app-application', labelJa: '確定終了メッセージ', labelEn: 'Confirm result message', table: 'TLN_M_GENERAL_APP' },
'IS_EXECUTE_CONFIRM': { section: 'app-application', labelJa: '確定ボタン確認ダイアログ', labelEn: 'Confirm dialog', table: 'TLN_M_GENERAL_APP' },
'EXE_DISP_INIT_FLG': { section: 'app-application', labelJa: '確定後再表示オプション', labelEn: 'Post-confirm redisplay option', table: 'TLN_M_GENERAL_APP' },
'EXE_TARGET_ONLY_FLG_NO_SEARCH': { section: 'app-application', labelJa: '確定後再表示オプション', labelEn: 'Post-confirm redisplay option', table: 'TLN_M_GENERAL_APP' },
'EXE_DISP_TARGET_ONLY_FLG': { section: 'app-application', labelJa: '確定後再表示オプション', labelEn: 'Post-confirm redisplay option', table: 'TLN_M_GENERAL_APP' },
'IS_EXE_AUTH': { section: 'app-application', labelJa: '確定時認証', labelEn: 'Confirm-time authentication', table: 'TLN_M_GENERAL_APP' },
'SEND_MAIL': { section: 'app-application', labelJa: '確定後のメール送信', labelEn: 'Send mail after confirm', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEND_MAIL_': { section: 'app-application', labelJa: '確定後のメール送信', labelEn: 'Send mail after confirm', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVA_SCRIPT_ENGINE': { section: 'app-application', labelJa: 'DB検索JavaScript', labelEn: 'DB search JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PL_SQL_NAME_SEARCH': { section: 'app-application', labelJa: 'DB検索プロシージャ名', labelEn: 'DB search procedure name', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_SEARCH_AFTER': { section: 'app-application', labelJa: 'DB検索プロシージャ名', labelEn: 'DB search procedure name', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME': { section: 'app-application', labelJa: 'プロシージャ名', labelEn: 'Procedure name', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_AFTER': { section: 'app-application', labelJa: 'プロシージャ名', labelEn: 'Procedure name', table: 'TLN_M_GENERAL_APP' },
'ACCESS_DB': { section: 'app-application', labelJa: 'DB接続先', labelEn: 'DB connection', table: 'TLN_M_GENERAL_APP' },
'JAVA_SCRIPT': { section: 'app-application', labelJa: 'Client-side JavaScript', labelEn: 'Client-side JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSS': { section: 'app-application', labelJa: 'CSS', labelEn: 'CSS', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JOIN': { section: 'app-application', labelJa: '結合項目', labelEn: 'Join items', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_DSP_POS': { section: 'app-application', labelJa: 'ボタン位置移動', labelEn: 'Button position', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_REPORT': { section: 'app-report', labelJa: 'EXCEL', labelEn: 'Excel', table: 'TLN_M_GENERAL_ITEM_OPTN' },
// ALL_OPT は BUTTON_REPORT.COL_NAME の値 (= 「追加オプション」) であり FUNC_KBN ではない。
// 表示は subCategoryPrefix (update-before.server.js) で COL_NAME='ALL_OPT' 検出時に解決する。
'BUTTON_NEXT': { section: 'app-othernext', labelJa: '機能画面設定', labelEn: 'Function screen setting', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX': { section: 'app-ajax', labelJa: 'ボタン名', labelEn: 'Button name', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX_CLIENT_JAVASCRIPT': { section: 'app-ajax', labelJa: '再表示ブロック', labelEn: 'Refresh block', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_AJAX_': { section: 'app-ajax', labelJa: 'DB検索前JavaScript', labelEn: 'Pre-search JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CR_FLG_SEARCH': { section: 'block-item', labelJa: '検索改行', labelEn: 'Search line break', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'REQUIRED_SEARCH': { section: 'block-item', labelJa: '検索必須', labelEn: 'Search required', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'IS_DB_NOT_REGIST': { section: 'block-item', labelJa: 'DB更新無し', labelEn: 'No DB update', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TABLE_LAYOUT': { section: 'block-item', labelJa: 'ROW SPAN', labelEn: 'ROW SPAN', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TABLE_TITLE_LAYOUT': { section: 'block-item', labelJa: 'タイトルROW SPAN', labelEn: 'Title ROW SPAN', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEARCH_METHOD': { section: 'block-item', labelJa: '検索方式', labelEn: 'Search method', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'DISP_POS': { section: 'block-item', labelJa: '表示位置', labelEn: 'Display position', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TAB_INDEX_SEARCH': { section: 'block-item', labelJa: 'Tab index(検索)', labelEn: 'Tab index (search)', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TAB_INDEX': { section: 'block-item', labelJa: 'Tab index', labelEn: 'Tab index', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CAMMA_OFF': { section: 'block-item', labelJa: 'カンマ編集無し', labelEn: 'No comma editing', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'ZERO_SPLIT': { section: 'block-item', labelJa: '小数点ゼロ埋め', labelEn: 'Pad decimals with zero', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'ALL_SELECT_CHECK': { section: 'block-item', labelJa: 'コンポーネント', labelEn: 'Component', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TATE_CHECK': { section: 'block-item', labelJa: 'コンポーネント', labelEn: 'Component', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OPTION_LIST_FUNC_ID': { section: 'block-item', labelJa: 'オプションリスト機能ID', labelEn: 'Option list function ID', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OPTION_LIST_SEARCH': { section: 'block-item', labelJa: 'オプションリスト機能ID', labelEn: 'Option list function ID', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CLASS_CODE': { section: 'block-item', labelJa: '階層コード/レベル', labelEn: 'Hierarchy code / level', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'NEST': { section: 'block-item', labelJa: '階層コード/レベル', labelEn: 'Hierarchy code / level', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INPUT_CONDITION': { section: 'block-item', labelJa: '入力許可パターン', labelEn: 'Input allow pattern', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MATCH_PATTERN': { section: 'block-item', labelJa: '入力チェックパターン', labelEn: 'Input check pattern', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SEARCH_FUNC_ID': { section: 'block-item', labelJa: '検索子画面', labelEn: 'Sub search screen', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUB_SEARCH': { section: 'block-item', labelJa: '検索子画面', labelEn: 'Sub search screen', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUB_BTN_HDN': { section: 'block-item', labelJa: '子画面非表示', labelEn: 'Sub screen hidden', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MASTER_CHECK': { section: 'block-item', labelJa: 'マスタチェック', labelEn: 'Master check', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LOOK_UP_FUNC_ID': { section: 'block-item', labelJa: 'LOOKUP', labelEn: 'LOOKUP', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LOOK_UP': { section: 'block-item', labelJa: 'LOOKUP', labelEn: 'LOOKUP', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FOCUS_OUT_JAVASCRIPT': { section: 'block-item', labelJa: 'FOCUS OUT', labelEn: 'FOCUS OUT', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FLAT_TEXT': { section: 'block-item', labelJa: '値保持', labelEn: 'Value retention', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUGGEST_FUNC_ID': { section: 'block-item', labelJa: 'SUGGEST', labelEn: 'SUGGEST', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SUGGEST': { section: 'block-item', labelJa: 'SUGGEST', labelEn: 'SUGGEST', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'PRINTING_UPDATE': { section: 'block-item', labelJa: '印刷時更新項目', labelEn: 'Print-time update items', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FORE_COLOR': { section: 'block-item', labelJa: '文字色', labelEn: 'Foreground color', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BACK_COLOR': { section: 'block-item', labelJa: '背景色', labelEn: 'Background color', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INIT_VALUE_TEXT': { section: 'block-item', labelJa: '検索条件初期値', labelEn: 'Search initial value', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'INIT_VALUE': { section: 'block-item', labelJa: '検索条件初期値', labelEn: 'Search initial value', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'REGIST_VALUE': { section: 'block-item', labelJa: 'DB設定式', labelEn: 'DB set formula', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FIX_FORMULA': { section: 'block-item', labelJa: '固定条件式', labelEn: 'Fixed condition formula', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SAIBAN_SIKIBETU_CODE': { section: 'block-item', labelJa: '採番名', labelEn: 'Numbering name', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'SERIAL_NUMBER_VAL': { section: 'block-item', labelJa: 'シリアル番号加算値', labelEn: 'Serial number increment', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVASCRIPT': { section: 'block-item', labelJa: 'JavaScript呼出ボタン', labelEn: 'JavaScript call button', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'JAVASCRIPT_ENGINE': { section: 'block-item', labelJa: 'JavaScript呼出ボタン', labelEn: 'JavaScript call button', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BARCODE_FORMAT': { section: 'block-item', labelJa: 'EXCEL帳票', labelEn: 'Excel report', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'THUMBNAIL_SIZE': { section: 'block-item', labelJa: 'サムネイル・バーコードサイズ', labelEn: 'Thumbnail / barcode size', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'IMG_UPLOAD_SIZE': { section: 'block-item', labelJa: 'アップロードファイルサイズ', labelEn: 'Upload file size', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'DRILL_DOWN': { section: 'block-item', labelJa: 'ドリルダウンレベル項目', labelEn: 'Drill-down level item', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'HDN_LIST_SORT': { section: 'block-item', labelJa: '明細ソート無し', labelEn: 'No row sorting', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'TITLE_NOTE': { section: 'block-item', labelJa: 'タイトルツールチップ', labelEn: 'Title tooltip', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'MAX_LINE_COUNT': { section: 'block-detail', labelJa: '画面最大行数', labelEn: 'Max rows on screen', table: 'TLN_M_GENERAL_APP' },
'MAX_LINE_COUNT_EXCEL': { section: 'block-detail', labelJa: '標準Excel出力最大行数', labelEn: 'Standard Excel max rows', table: 'TLN_M_GENERAL_APP' },
'MAX_LINE_CNT_EXCEL_UPDATE': { section: 'block-detail', labelJa: '更新Excel出力最大行数', labelEn: 'Update Excel max rows', table: 'TLN_M_GENERAL_APP' },
'ADD_LINE_VAL_INIT': { section: 'block-detail', labelJa: '追加行の初期値', labelEn: 'Initial values for added rows', table: 'TLN_M_GENERAL_APP' },
'STD_EXCEL_EXT': { section: 'block-detail', labelJa: '標準Excel拡張子', labelEn: 'Standard Excel extension', table: 'TLN_M_GENERAL_APP' },
'LIST_PAGE_ROWS': { section: 'block-detail', labelJa: '初期ページ内行数', labelEn: 'Initial rows per page', table: 'TLN_M_GENERAL_APP' },
'LIST_PAGE_DROPDOWN': { section: 'block-detail', labelJa: '改頁行数選択リスト', labelEn: 'Rows-per-page dropdown list', table: 'TLN_M_GENERAL_APP' },
'SPACE_HEIGHT': { section: 'block-detail', labelJa: '表示高さ', labelEn: 'Display height', table: 'TLN_M_GENERAL_APP' },
'IS_VERTICAL_LAYOUT': { section: 'block-detail', labelJa: '行見出しレイアウト', labelEn: 'Row header layout', table: 'TLN_M_GENERAL_APP' },
'HDN_PAGER_FLG': { section: 'block-detail', labelJa: '改ページしない', labelEn: 'No pagination', table: 'TLN_M_GENERAL_APP' },
'BLOCK_NAME_HDN_FLG': { section: 'block-detail', labelJa: 'ブロック名フィールドを非表示', labelEn: 'Hide block name field', table: 'TLN_M_GENERAL_APP' },
'IS_SEARCH_NOTFOUND_MSG_HDN': { section: 'block-detail', labelJa: '検索結果0件メッセージを非表示', labelEn: 'Hide no-results message', table: 'TLN_M_GENERAL_APP' },
'IS_CLOSE_SWITCH': { section: 'block-detail', labelJa: '開閉表示状態', labelEn: 'Open/close state', table: 'TLN_M_GENERAL_APP' },
'IS_LIST_ROW_SELECT': { section: 'block-detail', labelJa: '明細行の編集方式', labelEn: 'Row edit mode', table: 'TLN_M_GENERAL_APP' },
'IS_LIST_FIXED': { section: 'block-detail', labelJa: '明細列の固定', labelEn: 'Pinned columns', table: 'TLN_M_GENERAL_APP' },
'EXCELUPDATE_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'VIEW_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'COL_BUTTON_HDN_FLG': { section: 'block-detail', labelJa: 'ボタンの非表示', labelEn: 'Button (hidden)', table: 'TLN_M_GENERAL_APP' },
'EXCELUPDATE_BTN_DISABLED_FLG': { section: 'block-detail', labelJa: '検索前ボタンの非活性', labelEn: 'Disable button before search', table: 'TLN_M_GENERAL_APP' },
'INSERT_FLG': { section: 'block-detail', labelJa: '処理権限', labelEn: 'Process permission', table: 'TLN_M_GENERAL_APP' },
'UPDATE_FLG': { section: 'block-detail', labelJa: '処理権限', labelEn: 'Process permission', table: 'TLN_M_GENERAL_APP' },
'DELETE_FLG': { section: 'block-detail', labelJa: '処理権限', labelEn: 'Process permission', table: 'TLN_M_GENERAL_APP' },
'EXCLUSIVE_CONTROL_FLG': { section: 'block-detail', labelJa: '確定時オプション', labelEn: 'Confirm option', table: 'TLN_M_GENERAL_APP' },
'ALL_REG_FLG': { section: 'block-detail', labelJa: '確定時オプション', labelEn: 'Confirm option', table: 'TLN_M_GENERAL_APP' },
'IS_USE_SEARCH_RESULT_REPORT': { section: 'block-detail', labelJa: '確定時オプション', labelEn: 'Confirm option', table: 'TLN_M_GENERAL_APP' },
'IS_USE_SEARCH_RESULT_MAIL': { section: 'block-detail', labelJa: '確定時オプション', labelEn: 'Confirm option', table: 'TLN_M_GENERAL_APP' },
'PLSQL_PARAM_COL': { section: 'block-detail', labelJa: 'プロシージャ名', labelEn: 'Procedure name', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'LISTSELECT_BTN_CND': { section: 'block-detail', labelJa: '参照ボタン', labelEn: 'View button', table: 'TLN_M_GENERAL_APP' },
'LISTSEL_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '参照ボタン', labelEn: 'View button', table: 'TLN_M_GENERAL_APP' },
'COPY_DL_BTN_CND': { section: 'block-detail', labelJa: '複写ボタン', labelEn: 'Copy button', table: 'TLN_M_GENERAL_APP' },
'COPY_DL_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '複写ボタン', labelEn: 'Copy button', table: 'TLN_M_GENERAL_APP' },
'ADDLINE_DL_BTN_CND': { section: 'block-detail', labelJa: '行追加ボタン', labelEn: 'Add-row button', table: 'TLN_M_GENERAL_APP' },
'ADDLINE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '行追加ボタン', labelEn: 'Add-row button', table: 'TLN_M_GENERAL_APP' },
'DELETE_BTN_CND': { section: 'block-detail', labelJa: '削除ボタン', labelEn: 'Delete button', table: 'TLN_M_GENERAL_APP' },
'DELETE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '削除ボタン', labelEn: 'Delete button', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CODE_': { section: 'block-detail', labelJa: '行文字色', labelEn: 'Row foreground color', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_KBN_': { section: 'block-detail', labelJa: '行文字色', labelEn: 'Row foreground color', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CND_': { section: 'block-detail', labelJa: '行文字色', labelEn: 'Row foreground color', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_CODE_': { section: 'block-detail', labelJa: '行背景色', labelEn: 'Row background color', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_KBN_': { section: 'block-detail', labelJa: '行背景色', labelEn: 'Row background color', table: 'TLN_M_GENERAL_APP' },
'BACK_COLOR_TR_CND_': { section: 'block-detail', labelJa: '行背景色', labelEn: 'Row background color', table: 'TLN_M_GENERAL_APP' },
'SAVE_BTN_CND': { section: 'block-detail', labelJa: '保存ボタン', labelEn: 'Save button', table: 'TLN_M_GENERAL_APP' },
'SAVE_BTN_NAME_DISP_FORMULA': { section: 'block-detail', labelJa: '保存ボタン', labelEn: 'Save button', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TITLE_COL': { section: 'block-detail', labelJa: 'タスクコード', labelEn: 'Task code', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_GRID_TOP': { section: 'block-detail', labelJa: '時間グリッドのスクロールTOP', labelEn: 'Time grid scroll TOP', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_FROM_DATE_COL': { section: 'block-detail', labelJa: '開始日時', labelEn: 'Start datetime', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TO_DATE_COL': { section: 'block-detail', labelJa: '終了日時', labelEn: 'End datetime', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_START_WEEK': { section: 'block-detail', labelJa: '開始曜日', labelEn: 'Start day of week', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_INIT_SCALE': { section: 'block-detail', labelJa: '描画期間初期値', labelEn: 'Initial draw period', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_MONTH': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', labelEn: 'Scale button visibility', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_WEEK': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', labelEn: 'Scale button visibility', table: 'TLN_M_GENERAL_APP' },
'IS_SCALE_HIDDEN_DAY': { section: 'block-detail', labelJa: '描画期間スケールボタン表示', labelEn: 'Scale button visibility', table: 'TLN_M_GENERAL_APP' },
'IS_ALL_DAY_CHECK_ON': { section: 'block-detail', labelJa: 'All Day チェックボックス状態', labelEn: 'All-day checkbox state', table: 'TLN_M_GENERAL_APP' },
'CALENDAR_SIKIBETU_CODE': { section: 'block-detail', labelJa: 'カレンダー識別コード', labelEn: 'Calendar code', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_UPDATE_CONFIRM': { section: 'block-detail', labelJa: 'イベントバーの変更時確認', labelEn: 'Confirm bar update', table: 'TLN_M_GENERAL_APP' },
'IS_SCHEDULE_UIWAIT_LOCK': { section: 'block-detail', labelJa: '処理中ロック', labelEn: 'Lock while processing', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_TITLE_DISP_COL': { section: 'block-detail', labelJa: 'タスク表示名', labelEn: 'Task display name', table: 'TLN_M_GENERAL_APP' },
'IS_TASK_GROUING_DISP': { section: 'block-detail', labelJa: 'タスク名の全種表示', labelEn: 'Show all task names', table: 'TLN_M_GENERAL_APP' },
'TASK_AREA_WIDTH': { section: 'block-detail', labelJa: 'タスク領域幅', labelEn: 'Task area width', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_EVENT_TEXT_COL': { section: 'block-detail', labelJa: 'イベント内容項目', labelEn: 'Event content field', table: 'TLN_M_GENERAL_APP' },
'IS_FIT_EVENT_BAR_MAX_WIDTH': { section: 'block-detail', labelJa: 'イベント内容項目', labelEn: 'Event content field', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_EVENT_TOOLTIP_COL': { section: 'block-detail', labelJa: 'ツールチップ項目', labelEn: 'Tooltip field', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_UNIQUE_COL': { section: 'block-detail', labelJa: '関係線KEY項目', labelEn: 'Relation key field', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_CONNECT_FROM_COL': { section: 'block-detail', labelJa: '関係線FROM', labelEn: 'Relation FROM', table: 'TLN_M_GENERAL_APP' },
'SCHEDULE_CONNECT_TO_COL': { section: 'block-detail', labelJa: '関係線TO', labelEn: 'Relation TO', table: 'TLN_M_GENERAL_APP' },
'LABEL_DSP_CNT': { section: 'block-detail', labelJa: '日時ラベル最大表示数', labelEn: 'Max date labels', table: 'TLN_M_GENERAL_APP' },
'IS_GRID_SNAP_OFF': { section: 'block-detail', labelJa: 'イベントバーのグリッドスナップ', labelEn: 'Snap bar to grid', table: 'TLN_M_GENERAL_APP' },
'IS_ST_ED_TOOLTIP_HIDDEN': { section: 'block-detail', labelJa: '開始-終了日時ツールチップ', labelEn: 'Start/end datetime tooltip', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_MOUSE_ALLOW_RESIZING': { section: 'block-detail', labelJa: 'イベントバーのマウス操作', labelEn: 'Bar mouse interaction', table: 'TLN_M_GENERAL_APP' },
'IS_BAR_MOUSE_ALLOW_MOVING': { section: 'block-detail', labelJa: 'イベントバーのマウス操作', labelEn: 'Bar mouse interaction', table: 'TLN_M_GENERAL_APP' },
// GANTT 固有設定 (カタログ §7C 準拠): スケールボタン表示8種 + グリッド初期値8種 + 時間スケール3種
'IS_GANTT_DISP_HOUR_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 時ボタン表示', labelEn: 'Scale btn > Hour', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_DAY_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 日ボタン表示', labelEn: 'Scale btn > Day', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_WEEK_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 週ボタン表示', labelEn: 'Scale btn > Week', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_MONTH_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 月ボタン表示', labelEn: 'Scale btn > Month', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_QUARTERLY_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 四半期ボタン表示', labelEn: 'Scale btn > Quarter', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_HALF_YEAR_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 半年ボタン表示', labelEn: 'Scale btn > Half year', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_YEAR_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 年ボタン表示', labelEn: 'Scale btn > Year', table: 'TLN_M_GENERAL_APP' },
'IS_GANTT_DISP_YEARS_BTN': { section: 'block-detail', labelJa: 'スケールボタン > 複数年ボタン表示', labelEn: 'Scale btn > Multi-year', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 時グリッド', labelEn: 'Grid init > Hour', table: 'TLN_M_GENERAL_APP' },
'GANTT_DAY_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 日グリッド', labelEn: 'Grid init > Day', table: 'TLN_M_GENERAL_APP' },
'GANTT_WEEK_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 週グリッド', labelEn: 'Grid init > Week', table: 'TLN_M_GENERAL_APP' },
'GANTT_MONTH_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 月グリッド', labelEn: 'Grid init > Month', table: 'TLN_M_GENERAL_APP' },
'GANTT_QTR_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 四半期グリッド', labelEn: 'Grid init > Quarter', table: 'TLN_M_GENERAL_APP' },
'GANTT_HALF_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 半年グリッド', labelEn: 'Grid init > Half year', table: 'TLN_M_GENERAL_APP' },
'GANTT_ONE_YEAR_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 年グリッド', labelEn: 'Grid init > Year', table: 'TLN_M_GENERAL_APP' },
'GANTT_YEARS_GRID_INIT_VAL': { section: 'block-detail', labelJa: 'グリッド初期値 > 複数年グリッド', labelEn: 'Grid init > Multi-year', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_FROM_INIT_VAL': { section: 'block-detail', labelJa: '時間スケール > 時間FROM初期値', labelEn: 'Time scale > Hour FROM', table: 'TLN_M_GENERAL_APP' },
'GANTT_HOUR_LIMIT_INIT_VAL': { section: 'block-detail', labelJa: '時間スケール > 時間LIMIT初期値', labelEn: 'Time scale > Hour LIMIT', table: 'TLN_M_GENERAL_APP' },
'GANTT_YEARS_INIT_VAL': { section: 'block-detail', labelJa: '時間スケール > 複数年初期値', labelEn: 'Time scale > Multi-year', table: 'TLN_M_GENERAL_APP' },
'GANTT_REF_UPDATE_TABLE': { section: 'block-detail', labelJa: 'GANTT参照更新テーブル', labelEn: 'GANTT ref update table', table: 'TLN_M_GENERAL_APP' },
'BUTTON_BAT': { section: 'block-proc', labelJa: 'JavaScript', labelEn: 'JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_BAT_CLIENT_JAVASCRIPT': { section: 'block-proc', labelJa: 'JavaScript', labelEn: 'JavaScript', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_BAT_': { section: 'block-proc', labelJa: 'プロシージャ', labelEn: 'Procedure', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'BUTTON_NEXT_': { section: 'block-othernext', labelJa: '設定(機能ID指定あり)', labelEn: 'Settings (with function ID)', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON': { section: 'block-fileio', labelJa: 'ファイル出力', labelEn: 'File output', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_OPTION': { section: 'block-fileio', labelJa: 'ファイル出力', labelEn: 'File output', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_FILE': { section: 'block-fileio', labelJa: 'ファイル出力', labelEn: 'File output', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_OUT_BUTTON_COL': { section: 'block-fileio', labelJa: 'ファイル出力', labelEn: 'File output', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON': { section: 'block-fileio', labelJa: 'DB登録', labelEn: 'DB register', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_OPTION': { section: 'block-fileio', labelJa: 'DB登録', labelEn: 'DB register', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_FILE': { section: 'block-fileio', labelJa: 'DB登録', labelEn: 'DB register', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CSV_LOAD_BUTTON_COL': { section: 'block-fileio', labelJa: 'DB登録', labelEn: 'DB register', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OTHER_FUNC': { section: 'block-otherfunc', labelJa: '式', labelEn: 'Formula', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'OTHER_FUNC_': { section: 'block-otherfunc', labelJa: '項目設定', labelEn: 'Item setting', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'UPDATE_TABLE': { section: 'block-other', labelJa: 'SELECT式', labelEn: 'SELECT formula', table: 'TLN_M_GENERAL_APP' },
'OTHER_BLOCK_FUNC': { section: 'block-other', labelJa: '他ブロック', labelEn: 'Other block', table: 'TLN_M_GENERAL_APP' },
'CHART_MARK': { section: 'block-chart-series', labelJa: 'マーカー', labelEn: 'Marker', table: 'TLN_M_GENERAL_ITEM_OPTN' },
// CHART タブ群 (カタログ §8 準拠) — 全般 / 凡例 / X軸 / Y軸 / Y2軸 / 系列
'CHART_FUNC_INFO': { section: 'block-chart-base', labelJa: 'グラフ種類', labelEn: 'Chart type', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_BASE': { section: 'block-chart-base', labelJa: '全般', labelEn: 'General', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_LEGEND_BASE': { section: 'block-chart-base', labelJa: '凡例', labelEn: 'Legend', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_X_BASE': { section: 'block-chart-axis-x', labelJa: 'X軸 基本', labelEn: 'X axis', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_X_LABEL_BASE': { section: 'block-chart-axis-x', labelJa: 'X軸 タイトルラベル', labelEn: 'X axis label', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_X_TICK_BASE': { section: 'block-chart-axis-x', labelJa: 'X軸 目盛りラベル', labelEn: 'X axis tick', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_GRID_X_BASE': { section: 'block-chart-axis-x', labelJa: 'X軸 グリッド', labelEn: 'X axis grid', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_BASE': { section: 'block-chart-axis-y', labelJa: 'Y軸 基本', labelEn: 'Y axis', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_LABEL_BASE': { section: 'block-chart-axis-y', labelJa: 'Y軸 タイトルラベル', labelEn: 'Y axis label', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_TICK_BASE': { section: 'block-chart-axis-y', labelJa: 'Y軸 目盛りラベル', labelEn: 'Y axis tick', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_GRID_Y_BASE': { section: 'block-chart-axis-y', labelJa: 'Y軸 グリッド', labelEn: 'Y axis grid', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_R_BASE': { section: 'block-chart-axis-y2', labelJa: 'Y2軸 基本', labelEn: 'Y2 axis', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_R_LABEL_BASE': { section: 'block-chart-axis-y2', labelJa: 'Y2軸 タイトルラベル', labelEn: 'Y2 axis label', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_AXIS_Y_R_TICK_BASE': { section: 'block-chart-axis-y2', labelJa: 'Y2軸 目盛りラベル', labelEn: 'Y2 axis tick', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_SERIES_BASE': { section: 'block-chart-series', labelJa: '系列 基本', labelEn: 'Series', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_SERIES_ONCLICK': { section: 'block-chart-series', labelJa: '系列 ドリルダウン', labelEn: 'Series drill-down', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'CHART_SERIES_ONCLICK_WINSIZE': { section: 'block-chart-series', labelJa: '系列 ドリルダウン Window 寸法', labelEn: 'Drill-down window size', table: 'TLN_M_GENERAL_ITEM_OPTN' },
'FUNC_TOP_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_HEAD': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'CONDITION_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_TOP': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'RESULT_AREA': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'FUNC_BUTTON_AREA_BTM': { section: 'free-layout', labelJa: '機能実行画面デザイン', labelEn: 'Function screen design', table: 'TLN_M_GENERAL_POSITION' },
'BLOCK': { section: 'free-layout', labelJa: 'ブロックデザイン(明細)', labelEn: 'Block design (list)', table: 'TLN_M_GENERAL_POSITION' },
'CONDITION': { section: 'free-layout', labelJa: 'ブロックデザイン(検索条件)', labelEn: 'Block design (search)', table: 'TLN_M_GENERAL_POSITION' },
// === DB スキャンで未対応だった追加分 (TLN_M_GENERAL_APP) ===
'EXECUTE_BTN_DISP_NAME': { section: 'app-application', labelJa: '確定ボタン表示名', labelEn: 'Confirm button display name', table: 'TLN_M_GENERAL_APP' },
'HELP_LINK_NM': { section: 'app-application', labelJa: 'ヘルプリンク表示名', labelEn: 'Help link name', table: 'TLN_M_GENERAL_APP' },
'HELP_URL': { section: 'app-application', labelJa: 'ヘルプURL', labelEn: 'Help URL', table: 'TLN_M_GENERAL_APP' },
// === DB スキャンで未対応だった追加分 (TLN_M_GENERAL_ITEM_OPTN) ===
// ※ BUTTON_AJAX_<N>, BUTTON_BAT_<N>, BUTTON_NEXT_<N>, OTHER_FUNC_<N>, SEND_MAIL_<N> 系は
// _<digits> サフィックスのフォールバック解決でカバーされる (TFC.funcKbnInfo 参照)
// ※ PLOT / PLOT_BTN_CND / PLOT_COL / PLOT_COL_MARKER_STYLE / PLOT_COL_PIE_OPTION は
// TALON 6.2 ソースに存在せず削除 (CHART 系は CHART_BASE / CHART_SERIES_BASE 等に置き換え済)
'BUTTON_LIST_OPT': { section: 'block-otherfunc', labelJa: 'LIST明細選択ボタンオプション', labelEn: 'LIST row select button option', table: 'TLN_M_GENERAL_ITEM_OPTN' },
// === DB設定マスタ.csv (talon-docs) との突合で判明した追加分 ===
// 機能タブ アプリケーション (FUNC_SEQ=-1)
'SEARCH_FLG': { section: 'app-application', labelJa: '検索ボタン表示', labelEn: 'Show search button', table: 'TLN_M_GENERAL_APP' },
'CLEAR_FLG': { section: 'app-application', labelJa: 'クリアボタン表示', labelEn: 'Show clear button', table: 'TLN_M_GENERAL_APP' },
'EXCEL_OUT_FLG': { section: 'app-application', labelJa: 'Excel出力ボタン表示', labelEn: 'Show Excel out button', table: 'TLN_M_GENERAL_APP' },
'PDF_OUT_FLG': { section: 'app-application', labelJa: 'PDF出力ボタン表示', labelEn: 'Show PDF out button', table: 'TLN_M_GENERAL_APP' },
// ブロック設定 詳細 (FUNC_SEQ != -1) — _<N> サフィックス連番系の基底キーとして登録
'BACK_COLOR_TR_CODE': { section: 'block-detail', labelJa: '行背景色 動的キー', labelEn: 'Row background color (dynamic key)', table: 'TLN_M_GENERAL_APP' },
'FORE_COLOR_TR_CODE': { section: 'block-detail', labelJa: '行文字色 動的キー', labelEn: 'Row foreground color (dynamic key)', table: 'TLN_M_GENERAL_APP' },
// ブロック 検索呼出 (DLプロシージャ)
'PL_SQL_NAME_DL': { section: 'block-proc', labelJa: '検索前プロシージャ (引出)', labelEn: 'Pre-search procedure (DL)', table: 'TLN_M_GENERAL_APP' },
'PL_SQL_NAME_AFTER_DL': { section: 'block-proc', labelJa: '検索後プロシージャ (引出)', labelEn: 'Post-search procedure (DL)', table: 'TLN_M_GENERAL_APP' },
// 項目情報 (TLN_M_GENERAL_ITEM_OPTN)
'ZERO_INT': { section: 'block-item', labelJa: 'ゼロ値ハイフン表示', labelEn: 'Show hyphen for zero', table: 'TLN_M_GENERAL_ITEM_OPTN' },
};
// FUNC_KBN は同種設定が複数登録されると `_<N>` 連番サフィックスが付くことがある
// 例: BUTTON_NEXT, BUTTON_NEXT_0, BUTTON_NEXT_1, ... (同じ FUNC_KBN 系列を別レコードとして保持)
// この場合、辞書に基底キーがあればフォールバックで該当エントリを返す
function _resolveBaseKbn(funcKbn) {
if (!funcKbn) return null;
if (FUNC_KBN_DICT[funcKbn]) return FUNC_KBN_DICT[funcKbn];
// _<digits> 末尾を削って再検索
var m = funcKbn.match(/^(.+?)_(\d+)$/);
if (m && FUNC_KBN_DICT[m[1]]) return FUNC_KBN_DICT[m[1]];
return null;
}
TFC.funcKbnInfo = function (funcKbn) {
return _resolveBaseKbn(funcKbn);
};
TFC.isKnownFuncKbn = function (funcKbn) {
return _resolveBaseKbn(funcKbn) != null;
};
// FUNC_KBN コード → 「ラベル (コード)」形式の表示文字列。
// lang='en' で labelEn があればそれを使用、なければ labelJa にフォールバック。
// labelEn の翻訳率は段階的に上げる方針。
TFC.fkLabel = function (funcKbn, lang) {
var info = _resolveBaseKbn(funcKbn);
if (!info) return funcKbn || '';
var label = null;
if (lang === 'en' && info.labelEn) label = info.labelEn;
if (!label) label = info.labelJa;
return label ? (label + ' (' + funcKbn + ')') : (funcKbn || '');
};
// ============================================================
// HTML テンプレート部品
// ============================================================
// favicon: TALON ロゴを 32x32 PNG に縮小し base64 化したもの (data URL で各HTMLに埋め込み)
// 元画像: _local/talon_cs2 - ロゴ(イメージ).png (252x243 RGBA)
// _local/favicon_32.png 経由で生成 / 約 1.5KB → base64 約 2KB
TFC.FAVICON_DATA_URL = 'data:image/png;base64,' +
'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFxElEQVR42uWWXYgdZxnHf887X+fs2bPb' +
'PUk0bSLSFlFaP/ADxAvpBsWLNpRo2YJYK60liY3bbUwolV6cHCkI0qpUQ+1aP8CLyMYgNSUfbWyyF2KF' +
'VFHjYkWsF8KaZLO753POzLzzPl6cs5tuY9PdNb3yD8PMMMzz/Oed////vMI1hQr6ulsBEOWaY2zKY0o9' +
'pvrnatWst5RcU2L3P1tGhgKoA8NQ8IWDn7vEwy/eQaH8TZJWjiIUSoakOc53PjPtr351VRBRdh95B2Hh' +
'22B8wBKVApLGr3lq+ySDN0wRlT9OOmzxQ488uwi8D5ERwuIHyLogAkEBuq3rAFZP4MABAZSgWCYqfwE/' +
'hDyDUgXSOAMmEbMBPxrBpuCF4HLtSyMl7VryzCIipF0PsGsjsAQjOWkcY5MA1QzTCDA0e43o4rIMdRaX' +
'+ah2++8EhAWfLPYRgbAASctfH4E8FbxihPEMuTUYz6Aa9J9eR2EoQAkICmDnK1SrhgW7QLf1KjbNQAVj' +
'PNTW10fACxWhi+YBQobmAXgpAM4eozX/d7JOTtrxcPkluNXnqd+c4BZOUZy9bMlXnrHrdIEK1TMRjYvC' +
'0CalEQnt0DL5sWw9xlm7C/aeHGHR+zqm4tGwOdGAh8z/FjjMQyf2URi6kawNJvDJbYPvfvoR9r30UcKB' +
'+4mbDgxERYNNnubJbefW7oIkqTC4cT9+CDaBYhm69etR/QUTJ/dS2bqF+ix4AbQupcAjOL2V4vCDONez' +
'YXEIFmdPAefWnmCBsyTtJnHDoQ5cDrh5RJQ8fZy51ybpNmZJYgtyftkdcT0j6cQk7d61agqwdgIu8igM' +
'ljEmw9pDLJ6/nYXZx9h55HoGKqd54rZdpPF2NDdA1MtbNWACIAAJwASYnv7WRqB62ieJO8SNcRZmb6Ld' +
'ehSjN7Lh3b+kNPwXooG/8vALP+HcKzPYxICGlzXkVh6rFqGqcOCMR22bhZpj5zNzUHqVkc0HUe6kOGSw' +
'KSRtJbeg7jWma13ec+Rd5HkCQFuPk89/iDTudZZU8LN/Xt2GqsJhDHdLDsDOX21kcPBeYCdR6b2oQtIG' +
'dbaXD4HgbJv2+ZsZqOygOBLRbTdpDx+6mkXl6l8M7Dq6hWJxN8Y8QFTajE3ApvlSMAOCOsvgRp/Gv/dg' +
'3Tk2bJ1GFdpzCTYbxosrMPQR0k7vPb9oSJtn+cFdF/w3BIyHiAUsu45uoVTcA+YBwuIm0hjihgUxCN7r' +
'CDvCkk/70p+Y/d2zbP3kDHHT4jJQ5vje7Ql7T32K8qaf0Vns2bBQhqbsAJ7zL6+EKDUs901tYmTjXsSM' +
'U6oMksX0ppsPmntvWDXFGAdqSFv3cMMnHqU4fDOdxQQvDBBn+i7ISGOHTS2CkPoenrc0DbXX/MHnNxMW' +
'92PMOFEpJK7PUZ+dwUij32ozfvh+8hyW9l3qcoojPq25Jzj42T8zceLniAEviAgLEKeDPesaBXFAP4lE' +
'enWWXDB+bCte+EN80yDPdrN44WUS+y9+vKO5Qh8Tx79GVH6yr2YlGvRpL/ye2eZjjE15xM0vIVIhiR1Z' +
'W3C210XyEsUhH8395SRM22GfgCgcu0incxeTd3auHDwInDHUtlliDiGdbyHGw/g5Nu2Qtu7h8N0pVTXU' +
'5Ox/Dy9eJl7cR9pxqEpPuPrHK11QPd3XxKijhi7vaHvFla8e/SDhwB9wLqdY9mnO3cf3t/+U6mmf2jZL' +
'VQ0zhy/XvGVMqYlb7TSUZetdgTMGyPHCD+NHYHyf1sKPVjQH3rTZkrVXDLfRHBH1Vyj6zTBzUQFF3R0U' +
'ykL9wln42x7Gpjxqo/lb771Fl/aAy6itOv+rvbD58nPvZP90nf3Ti3zl+ZuWf83/iFUUGDWAUo6+yMDI' +
'EN3653l6+z+YUu+t/u+1gIAKt1V9Jl5sMX7sGyvF+nZjqdFDxx9n4uQLb0fzqxerjeZUqz4LLif2x0CF' +
'Gjn/f6iq6c2Ma4//AF9eqeub4bVbAAAAAElFTkSuQmCC';
TFC.FAVICON_LINK = '<link rel="icon" type="image/png" href="' + TFC.FAVICON_DATA_URL + '">';
TFC.htmlHead = function (titleText, lang) {
var l = lang || 'ja';
var t = TFC.escapeHtml(titleText);
return '<!DOCTYPE html>\n' +
'<html lang="' + l + '">\n' +
'<head>\n' +
'<meta charset="UTF-8">\n' +
'<meta name="viewport" content="width=device-width,initial-scale=1.0">\n' +
// ★ <head> 内で scrollRestoration=manual を確定 (戻る時の auto scroll と我々の scrollTo の競合を回避)
// <body> 末尾 script に置くと、ブラウザの auto restoration が先に走ってしまう。
'<script>if("scrollRestoration" in history){try{history.scrollRestoration="manual";}catch(e){}}</script>\n' +
TFC.FAVICON_LINK + '\n' +
'<title>' + t + '</title>\n' +
'<style>' + TFC.CSS + '</style>\n' +
'</head>\n<body>\n';
};
TFC.htmlTail = function () {
return '\n<script>' + TFC.JS_TAIL + '</script>\n</body>\n</html>\n';
};
TFC.tabBadge = function (isOn, count, lang) {
var l = (lang === 'en') ? 'en' : 'ja';
if (isOn) {
var unit = TFC.t('badge.unit', l);
var on = '● ' + TFC.t('badge.set', l) + ' (' + count + (unit ? ' ' + unit : '') + ')';
return '<span class="tab-status tab-status-on">' + on + '</span>';
}
return '<span class="tab-status tab-status-off">○ ' + TFC.t('badge.none', l) + '</span>';
};
TFC.htmlSection = function (titleHtml, bodyHtml, classes) {
var c = classes ? ' ' + classes : '';
var body = bodyHtml || '';
// body 内に展開可能 <details> が複数含まれる場合、タブ単位の「全展開/全閉じる」
// ツールバーを上部に自動付加。tab-on (= 設定あり) のセクションのみ対象。
var isOn = c.indexOf('tab-on') >= 0;
if (isOn && (body.match(/<details/g) || []).length >= 2) {
var lang = (typeof TFC.LANG === 'string' && TFC.LANG) ? TFC.LANG : 'ja';
var btnLblExp = (lang === 'en') ? 'Expand all' : '全て展開';
var btnLblCls = (lang === 'en') ? 'Collapse all' : '全て閉じる';
body = '<div class="tfc-item-toolbar">' +
'<button class="tfc-item-toolbar-btn" onclick="tfcTabExpandAll(this)">▶ ' + btnLblExp + '</button>' +
'<button class="tfc-item-toolbar-btn" onclick="tfcTabCollapseAll(this)">▼ ' + btnLblCls + '</button>' +
'</div>' + body;
}
return '<details class="screen-section' + c + '">\n' +
'<summary>' + titleHtml + '</summary>\n' +
'<div class="section-body">\n' + body + '\n</div>\n' +
'</details>\n';
};
// よくある「タブセクション = ラベル + バッジ + body」パターンの便利ラッパ。
// labelKey: TFC.t() のキー (例: 'sec.funcDesc')
// bodyHtml: セクション本文 (空文字列なら off 扱い)
// count: バッジ件数 (省略時は body が空でなければ 1 扱い)
// lang: 'ja' | 'en'
// body が空なら tab-off + 件数 0、そうでなければ tab-on + 件数 N を表示する。
TFC.tabSection = function (labelKey, bodyHtml, count, lang) {
var hasBody = bodyHtml != null && String(bodyHtml).length > 0;
var n = (count == null) ? (hasBody ? 1 : 0) : count;
var on = n > 0 && hasBody;
var summary = TFC.t(labelKey, lang) + ' ' + TFC.tabBadge(on, n, lang);
return TFC.htmlSection(summary, hasBody ? bodyHtml : '', on ? 'tab-on' : 'tab-off');
};
/* 初期表示: 全設定タブは func-card (1レベル目) のみ open、内側はすべて close
全展開・全閉じ・カードのみ・設定ありのみ等の操作は controls ボタンから行う
★ 注意: 「全閉じ」は FuncDoc.html (details.func-card がある画面) でしか望ましくない。
Domains.html / DomainMatrix.html / er-diagram.html 等の他ページでは details
の構造が違うので、 func-card が無い場合はこのロジック自体をスキップする。 */
TFC.JS_TAIL =
"document.addEventListener('DOMContentLoaded',function(){" +
// FuncDoc.html (= details.func-card を持つ) でのみ全閉じ + カード展開を行う。
// 他ページでは details の初期状態を尊重 (HTML の open 属性に従う)
"if(document.querySelector('details.func-card')){" +
"document.querySelectorAll('details').forEach(function(d){d.open=false;});" +
"document.querySelectorAll('details.func-card,details.shared-card').forEach(function(d){d.open=true;});" +
"}" +
// コードブック sidebar クリック → 対象コードブロックへスムーズスクロール + フラッシュ表示
"document.querySelectorAll('.tfc-cb-side a').forEach(function(a){" +
"a.addEventListener('click',function(ev){" +
"var hr=a.getAttribute('href')||'';" +
"if(hr.charAt(0)!=='#')return;" +
"var tgt=document.getElementById(hr.substring(1));" +
"if(!tgt)return;" +
"ev.preventDefault();" +
"document.querySelectorAll('.tfc-cb-side a.tfc-cb-active').forEach(function(x){x.classList.remove('tfc-cb-active');});" +
"a.classList.add('tfc-cb-active');" +
"document.querySelectorAll('.tfc-fn-block.tfc-fn-target').forEach(function(x){x.classList.remove('tfc-fn-target');});" +
"tgt.classList.add('tfc-fn-target');" +
"tgt.scrollIntoView({behavior:'smooth',block:'start'});" +
"});" +
"});" +
"});" +
"function tfcAll(open){document.querySelectorAll('details').forEach(function(d){d.open=open;});}" +
"function tfcCardOnly(){document.querySelectorAll('details.func-card,details.shared-card').forEach(function(d){d.open=true;});" +
"document.querySelectorAll('details.func-card details, details.shared-card details').forEach(function(d){d.open=false;});}" +
"function tfcOnOnly(){document.querySelectorAll('details').forEach(function(d){d.open=true;});" +
"document.querySelectorAll('details.tab-off').forEach(function(d){d.open=false;});}";
// 仕様書 §8 の色パレットを採用
TFC.CSS = "body{font-family:'Segoe UI',Meiryo,sans-serif;background:#f1f5f9;color:#1e293b;margin:0;padding:0 12px 32px;line-height:1.55}" +
"h1{font-size:1.5em;margin:18px 0 8px}" +
".meta{font-size:.9em;color:#475569;margin-bottom:6px}" +
".legend{font-size:.85em;color:#475569;margin:6px 0}" +
".controls{position:sticky;top:0;background:#fff;padding:8px;border-bottom:1px solid #cbd5e1;z-index:10;margin-bottom:12px}" +
".controls button{margin-right:6px;padding:4px 10px;font-size:.9em;cursor:pointer;border:1px solid #94a3b8;background:#f8fafc;border-radius:3px}" +
".controls button:hover{background:#e2e8f0}" +
"details.func-card{border:2px solid #cbd5e1;border-radius:6px;background:#fff;margin:14px 0;padding:6px 10px}" +
"details.func-card[open]{border-color:#7dd3fc}" +
"details.func-card>summary{font-weight:bold;font-size:1.1em;cursor:pointer;padding:4px 0}" +
"details.shared-card{border:2px solid #f59e0b;border-radius:6px;background:#fef3c7;margin:14px 0;padding:6px 10px}" +
"details.block-card{border:1px solid #7dd3fc;border-radius:4px;margin:8px 0;padding:4px 8px;background:#f0f9ff}" +
"details.screen-section{border:1px solid #e2e8f0;border-radius:3px;margin:6px 0;padding:4px 8px;background:#f8fafc}" +
"details.screen-section.tab-on{border-color:#86efac;background:#f0fdf4}" +
"details.screen-section.tab-off{border-color:#e2e8f0;background:#f8fafc;opacity:.85}" +
"details>summary{cursor:pointer;outline:none}" +
".tab-status{font-size:.85em;margin-left:8px}" +
".tab-status-on{color:#15803d}" +
".tab-status-off{color:#94a3b8}" +
".section-body{padding:6px 0 6px 12px}" +
"table.kv{border-collapse:collapse;margin:4px 0;width:auto}" +
"table.kv th,table.kv td{border:1px solid #cbd5e1;padding:3px 8px;font-size:.92em;text-align:left;vertical-align:top}" +
"table.kv th{background:#f1f5f9;color:#475569;white-space:nowrap;min-width:160px}" +
"table.kv td.val{background:#fff}" +
"table.kv td.kv-code{background:#f8fafc;color:#64748b;font-size:.78em;width:1%;white-space:nowrap;font-family:Consolas,monospace}" +
"table.kv-compact{table-layout:auto;width:auto}" +
"table.kv-compact th{min-width:0;padding:2px 6px;white-space:nowrap;font-size:.85em}" +
"table.kv-compact td{padding:2px 6px;font-size:.88em;white-space:nowrap;max-width:280px;overflow:hidden;text-overflow:ellipsis}" +
"table.kv-compact td:hover{overflow:visible;white-space:normal;background:#fef3c7}" +
"code,pre{font-family:Consolas,'Courier New',monospace}" +
"pre.sql-code,pre.js-code{background:#0f172a;color:#a5f3fc;padding:8px 10px;border-radius:4px;overflow:auto;font-size:.85em;margin:4px 0;white-space:pre-wrap;word-break:break-word}" +
"details.tfc-code-box{display:block;margin:4px 0;border-left:3px solid #38bdf8;padding-left:8px;background:#f0f9ff}" +
"details.tfc-code-box>summary{cursor:pointer;color:#0369a1;font-weight:bold;padding:4px 6px;list-style:none}" +
"details.tfc-code-box>summary::-webkit-details-marker{display:none}" +
"details.tfc-code-box>summary::before{content:'\\25B8';display:inline-block;margin-right:6px;transition:transform .15s}" +
"details.tfc-code-box[open]>summary::before{transform:rotate(90deg)}" +
"details.tfc-code-box .tfc-code-len{color:#64748b;font-weight:normal;font-size:.85em}" +
".kbn{display:inline-block;background:#fef3c7;color:#b45309;padding:1px 6px;border-radius:3px;font-size:.82em;font-family:Consolas,monospace}";
// ============================================================
// PG 由来 SELECT 結果の キー大文字化 (DB 横断対応)
// PostgreSQL は bare alias を lowercase 化するため、 row['FUNC_ID'] (uppercase 直書き)
// ではアクセスできない。 全 row を JS object に変換 + キーを uppercase 化して、
// コード本体は DB 種別を意識せず row['FUNC_ID'] で書けるようにする。
// - TALON.select() / TALON.getBlockData_List() 等の戻り値はすべて selectU 経由が望ましい
// - 副作用なしの純粋な正規化 (元の Java Map は変更しない)
// ============================================================
TFC.normalizeRows = function (rows) {
if (rows == null) return rows;
var n = (typeof rows.size === 'function') ? rows.size() : rows.length;
for (var ni = 0; ni < n; ni++) {
var src = rows[ni];
if (src == null) continue;
if (typeof src.entrySet !== 'function') continue; // 既に純 JS object 化済
var dst = {};
var iter = src.entrySet().iterator();
while (iter.hasNext()) {
var e = iter.next();
dst[String(e.getKey()).toUpperCase()] = e.getValue();
}
if (typeof rows.set === 'function') rows.set(ni, dst);
}
return rows;
};
// TFC.selectU(sql): TALON.select() のラッパで返り値を normalize する。
// DB 横断の SELECT は必ずこれを使うこと (PG / SQL Server / MySQL / Oracle 共通)
// ※ ユーザー入力を含む WHERE 句がある場合は TFC.selectPS (PreparedStatement) を使うこと。
TFC.selectU = function (sql) { return TFC.normalizeRows(TALON.select(sql)); };
// TFC.selectUByConn(conn, sql): 任意の DB 接続 (= 複数DB接続の外部 DB) で SELECT。
// conn は TALON.getOtherDBConn("N") (N=1..15) で取得する TalonConfig。
// 主 TALON DB の場合は TFC.selectU でも TALON.getDbConfig() でも可。
// manual §5.20.10 / API 4.8.3 準拠。
//
// Nashorn ではグローバル TalonDbUtil が利用可能 (TALON が import 済)。
// 存在判定は typeof で行う (Java.type 解決の package パスに依存しない)。
TFC.selectUByConn = function (conn, sql) {
if (!conn) return TFC.selectU(sql);
if (typeof TalonDbUtil === 'undefined') {
// フォールバック: TalonDbUtil グローバルが見つからない → 主 DB の TALON.select で代替
try { TALON.getLogger().writeWarn('[TFC] selectUByConn: TalonDbUtil グローバル未定義 → 主 DB で代替'); } catch (ig) {}
return TFC.selectU(sql);
}
return TFC.normalizeRows(TalonDbUtil.select(conn, sql));
};
// ============================================================
// SQL インジェクション対策 (PreparedStatement パターン)
// セキュア設定マニュアル「6.1. SQLインジェクション対応」の
// V6.2.18 以前バージョン向け実装に準拠。
// ユーザー入力 (検索条件・チェック行の値・URL パラメータ等) を SQL に
// 組み込む箇所では 必ず TFC.selectPS / TFC.updatePS を使うこと。
//
// 使い方:
// var rows = TFC.selectPS(
// "SELECT FUNC_ID, FUNC_NM FROM TLN_M_GENERAL_FUNC WHERE FUNC_ID = ?",
// [funcId] // ← JS Array で OK
// );
// // rows: [{FUNC_ID: 'TLN_FUNC_DOC', FUNC_NM: '...'}, ...] (キーは uppercase 正規化済)
//
// var cnt = TFC.updatePS(
// "UPDATE tln_m_general_item SET col_name = ? WHERE func_id = ? AND col_name = ?",
// [lowerNm, funcId, upperNm]
// );
// ============================================================
var _HashMap = Java.type('java.util.HashMap');
// 内部: Connection 取得 (トランザクション未開始時は beginTransaction)
function _getConn(dbConfig) {
try {
return dbConfig.getDataSource().getConnection();
} catch (e) {
// トランザクション未開始 (0S100 の ZIP 組立フェーズ / probe の begin→rollback 直後 / commit 直後) の再開。
// ★TALON が JS に注入する TalonDbUtil には beginTransaction が無い (呼ぶと TypeError — 2026-09-16 実測)。
// 従来はそれを握りつぶして 2 回目の getConnection が DOMA2048 で落ち、 ライセンス未配置 (①) では
// サーバ保存の設定読取がここで失敗して ZIP ダウンロードに黙って戻っていた。 DbConfig 自身の begin()
// (probe と同じ API。 既に begin 済なら throw するので無視) で開始する。 主 DB のトランザクションは
// TALON が機能終了時に終了させるため、 ここでは rollback しない
var began = false;
try { dbConfig.begin(); began = true; } catch (eB) { /* 既に begin 済 */ }
if (!began) {
try { TalonDbUtil.beginTransaction(dbConfig); } catch (e2) { /* 注入オブジェクトには無い */ }
}
return dbConfig.getDataSource().getConnection();
}
}
// 内部: PreparedStatement にパラメータを bind (setObject で型自動判別)
function _bindParams(stmt, params) {
if (params == null) return;
var n = (typeof params.length === 'function') ? params.length() :
(typeof params.length === 'number' ? params.length : params.size());
for (var i = 0; i < n; i++) {
var v = (typeof params.get === 'function') ? params.get(i) : params[i];
stmt.setObject(i + 1, v);
}
}
// 内部: ResultSet を [{COL_NAME: value, ...}, ...] 形式 (uppercase キー) で読み出し
function _readResultSet(rs) {
var md = rs.getMetaData();
var nc = md.getColumnCount();
var result = [];
while (rs.next()) {
var row = {};
for (var c = 1; c <= nc; c++) {
// getColumnLabel は AS 句の alias も取れる。 PG では lowercase で返るが
// uppercase に正規化して DB 横断対応とする。
row[String(md.getColumnLabel(c)).toUpperCase()] = rs.getObject(c);
}
result.push(row);
}
// selectU (Java List) との互換性のため size() メソッドを生やす
result.size = function () { return this.length; };
return result;
}
/**
* SELECT を PreparedStatement で実行 (SQL インジェクション安全).
* @param sql プレースホルダ「?」を含む SELECT 文
* @param params JS Array または java.util.ArrayList (省略可)
* @returns Array<{COL_NAME: value, ...}> (uppercase キー)
*/
TFC.selectPS = function (sql, params) {
var dbConfig = TALON.getDbConfig();
var conn = _getConn(dbConfig);
var stmt = null, rs = null;
try {
stmt = conn.prepareStatement(sql);
_bindParams(stmt, params);
rs = stmt.executeQuery();
return _readResultSet(rs);
} finally {
if (rs != null) { try { rs.close(); } catch (e) {} }
if (stmt != null) { try { stmt.close(); } catch (e) {} }
// Connection は TALON のトランザクション管理対象のため close しない
}
};
/**
* テーブルの列名一覧 (UPPER) を取得する (Ver0.51)。
*
* WHERE 1=0 の 0 行 SELECT の ResultSetMetaData から列名を得るため、
* 「列が無ければ失敗する SELECT を発行して catch で分岐」する方式と違い
* ★PostgreSQL のトランザクション汚染 (失敗文以降が 25P02 で全部失敗) を
* 起こさずにスキーマ差 (SETUP 前後 / 旧版列) を検出できる。
* 追加列のフォールバック分岐は必ずこちらを使うこと。
* @param tableName テーブル名 (内部固定値のみ。ユーザー入力を渡さない)
* @returns Array<string> 列名 (UPPER)。テーブル不在などは例外がそのまま伝播
*/
TFC.tableColumns = function (tableName) {
var dbConfig = TALON.getDbConfig();
var conn = _getConn(dbConfig);
var stmt = null, rs = null;
try {
stmt = conn.prepareStatement('SELECT * FROM ' + tableName + ' WHERE 1=0');
rs = stmt.executeQuery();
var md = rs.getMetaData();
var n = md.getColumnCount();
var out = [];
for (var i = 1; i <= n; i++) {
out.push(String(md.getColumnLabel(i)).toUpperCase());
}
return out;
} finally {
if (rs != null) { try { rs.close(); } catch (e) {} }
if (stmt != null) { try { stmt.close(); } catch (e) {} }
// Connection は TALON のトランザクション管理対象のため close しない
}
};
/**
* INSERT/UPDATE/DELETE を PreparedStatement で実行.
* @param sql プレースホルダ「?」を含む SQL
* @param params JS Array または java.util.ArrayList (省略可)
* @returns 影響行数 (int)
*/
TFC.updatePS = function (sql, params) {
var dbConfig = TALON.getDbConfig();
var conn = _getConn(dbConfig);
var stmt = null;
try {
stmt = conn.prepareStatement(sql);
_bindParams(stmt, params);
return stmt.executeUpdate();
} finally {
if (stmt != null) { try { stmt.close(); } catch (e) {} }
// Connection は閉じない (上記と同じ理由)
}
};
// ★No.292 (2026-10-14): 同じ SQL を多数回流すとき (EDM属性割当の作業表の作り直し = 属性カタログの行数ぶんの INSERT) は JDBC のバッチ
// (addBatch / executeBatch、 chunk 件ずつ) で往復を減らす。 戻り = 件数の合計 (SUCCESS_NO_INFO (-2) は 1 と数える)。 1 件でも失敗すると
// そのチャンクごと例外になるので、 主キーが重なり得る行は呼び出し側で先に除く。
TFC.updatePSBatch = function (sql, paramsList, chunk) {
var dbConfig = TALON.getDbConfig();
var conn = _getConn(dbConfig);
var stmt = null, total = 0, size = (chunk > 0) ? chunk : 500, pending = 0;
function tally(r) { for (var k = 0; k < r.length; k++) total += (r[k] > 0 ? r[k] : (r[k] === -2 ? 1 : 0)); }
try {
stmt = conn.prepareStatement(sql);
for (var i = 0; i < paramsList.length; i++) {
_bindParams(stmt, paramsList[i]);
stmt.addBatch(); pending++;
if (pending >= size) { tally(stmt.executeBatch()); pending = 0; }
}
if (pending > 0) tally(stmt.executeBatch());
return total;
} finally {
if (stmt != null) { try { stmt.close(); } catch (e) {} }
}
};
// ================================================================
// 画面文言の言語変換 (ja⇔en) — セットアップ画面の [日本語に変換]/[英語に変換]
//
// TALON は 1 機能内で機能名・項目名等の言語切替を持たないため、リポジトリの
// 表示値そのものを環境単位で書き換える (参考実装: ASP_SYS0010 change_language)。
// 標準メッセージ (CMN_W0008 等) はサーバ側で機能名・ブロックタイトルを合成する
// ので、DOM 書き換えではなくこの方式でないと言語が揃わない。
//
// - 正本 CSV は ja。リポジトリ再取込後は再度ボタンを押す運用
// - UI_LANG はキーベース対訳 (キー→[ja, en]) — ja⇔en 完全可逆
// - 対象は表示値のみ (機能名/ブロックTITLE/項目DISP_NAME/タブ・ボタンラベル/
// 製品汎用CD DSP1/宿題一覧 BODY_SQL の状態リテラル)。物理名・SQL構造・
// 顧客データには触れない。UPDATE は全て値ガード付き (現在値が対訳と一致する
// 行だけ書き換え = 冪等 & 利用者が変更した値はスキップ)
// - 現在言語 = 汎用CD TLN_FUNC_DOC_LANGUAGE/LANG の DSP1 ('ja'|'en')
// - ★変換後は デザイナ作り直し (verify_designer_roundtrip) でエラーなし・
// 差分ゼロが合格条件 (英語名は FUNC_NM<=50 / TITLE<=25 / DISP_NAME<=40 目安)
// ================================================================
var UI_LANG = {
FUNC_NM: {
// Ver1.0.6: 改訂履歴 2 画面
'TLN_FUNC_DOC_DOMAIN_HISTORY': ['Commonweal業務データ辞書履歴', 'Commonweal Business Data Dictionary History'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL': ['Commonweal業務データ辞書履歴照会', 'Commonweal Dictionary History Detail'],
'TLN_FUNC_DOC_EDM_HISTORY': ['Commonweal_EDM履歴', 'Commonweal EDM History'],
'TLN_FUNC_DOC_HIS_STATS': ['Commonweal改訂集計', 'Commonweal Revision Summary'],
'TLN_FUNC_DOC': ['Commonweal機能設計書出力', 'Commonweal Function Documents Output'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST': ['Commonweal業務データ辞書属性一覧', 'Commonweal Business Data Dictionary Attributes'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK': ['Commonweal物理属性CSV一括登録', 'Commonweal Physical Attribute CSV Bulk Registration'], // Ver1.0.22: 物理属性に戻す (ユーザー指示 2026-10-02)
'TLN_FUNC_DOC_DOMAIN_EDM_BULK': ['Commonweal_EDM属性CSV一括登録', 'Commonweal EDM Attribute CSV Bulk Registration'], // Ver1.0.22 新設
'TLN_FUNC_DOC_DOMAIN_BULK': ['Commonweal業務データ辞書CSV一括登録', 'Commonweal Business Data Dictionary CSV Bulk Registration'],
'TLN_FUNC_DOC_DOMAIN_EDIT': ['Commonweal業務データ辞書記入', 'Commonweal Business Data Dictionary Entry'],
'TLN_FUNC_DOC_DOMAIN_LIST': ['Commonweal業務データ辞書一覧', 'Commonweal Business Data Dictionary List'],
'TLN_FUNC_DOC_DOMAIN_TASKS': ['Commonweal業務データ辞書宿題一覧', 'Commonweal Business Data Dictionary Tasks'], // Ver1.0.18 復活
'TLN_FUNC_DOC_DOMAIN_MAINTE': ['Commonweal業務データ辞書メンテナンス', 'Commonweal Business Data Dictionary Maintenance'],
'TLN_FUNC_DOC_DOMAIN_SEARCH': ['Commonweal業務データ辞書検索', 'Commonweal Dictionary Search'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN': ['Commonweal_EDM属性割当', 'Commonweal EDM Attribute Assignment'],
'TLN_FUNC_DOC_EDM': ['Commonweal_EDMメンテナンス', 'Commonweal EDM Maintenance'],
'TLN_FUNC_DOC_EDM_ATTR_SUGGEST': ['Commonweal_EDM属性サジェスト', 'Commonweal EDM Attribute Suggest'],
'TLN_FUNC_DOC_EXCL_MAINTE': ['Commonweal照合除外メンテナンス', 'Commonweal Matching Exclusion Maintenance'],
'TLN_FUNC_DOC_EXCL_PICK': ['Commonweal照合除外登録', 'Commonweal Matching Exclusion Registration'],
'TLN_FUNC_DOC_SETUP': ['Commonwealセットアップ', 'Commonweal Setup']
},
TITLE: {
'TLN_FUNC_DOC_DOMAIN_HISTORY|0': ['業務データ辞書の履歴', 'Dictionary history'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1': ['物理属性の履歴', 'Physical attribute history'], // Ver1.0.20
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0': ['履歴の内容', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1': ['前の版', 'Previous revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2': ['この版の物理属性', 'Physical attributes of this revision'], // Ver1.0.15: 属性 → 物理属性
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3': ['この版のEDM属性', 'EDM attributes of this revision'], // Ver1.0.14 (Ver1.0.15: 定義域 → EDM属性)
'TLN_FUNC_DOC_EDM_HISTORY|0': ['EDMの履歴', 'EDM history'],
'TLN_FUNC_DOC_HIS_STATS|0': ['利用者別 (年月ごと)', 'By user (per month)'],
'TLN_FUNC_DOC_HIS_STATS|1': ['月別推移', 'Monthly trend'],
'TLN_FUNC_DOC_HIS_STATS|2': ['部門別 (年月ごと、現在の所属)', 'By dept (current)'], // Ver1.0.13 (No.175): 部門は現在のユーザマスタの所属
'TLN_FUNC_DOC|0': ['機能一覧', 'Functions'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0': ['属性一覧', 'Attributes'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0': ['物理属性一括編集', 'Physical attribute bulk edit'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0': ['EDM属性一括編集', 'EDM attribute bulk edit'],
'TLN_FUNC_DOC_DOMAIN_BULK|0': ['データドメイン一括編集', 'Data domain bulk edit'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0': ['業務データ辞書記入', 'Dictionary entry'],
'TLN_FUNC_DOC_DOMAIN_LIST|0': ['業務データ辞書', 'Business data dictionary'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0': ['宿題一覧', 'Tasks'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0': ['業務データ辞書', 'Business data dictionary'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1': ['属性明細', 'Attribute details'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2': ['EDM属性 (宣言とコメント)', 'EDM attributes (declared)'], // Ver1.0.14: 宣言の正本 (Ver1.0.15: 型・桁は廃止、 コメントだけ)
'TLN_FUNC_DOC_DOMAIN_SEARCH|0': ['業務データ辞書', 'Business data dictionary'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0': ['EDM属性割当 (属性名別)', 'EDM attribute assignment (by attribute)'], // Ver1.0.16: 2 タブ (Ver1.0.17: 属性名別)
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1': ['EDM属性割当 (エンティティ別)', 'EDM attribute assignment (by entity)'],
'TLN_FUNC_DOC_EDM|0': ['EDM情報', 'EDM info'],
'TLN_FUNC_DOC_EDM_ATTR_SUGGEST|0': ['EDM属性候補', 'EDM attr candidates'],
'TLN_FUNC_DOC_EXCL_MAINTE|0': ['照合除外', 'Matching exclusions'],
'TLN_FUNC_DOC_EXCL_PICK|0': ['テーブル別', 'By table'],
'TLN_FUNC_DOC_EXCL_PICK|1': ['列名別', 'By column']
},
DISP_NAME: {
// Ver1.0.6: 改訂履歴 2 画面
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|ATTR_NM': ['物理属性名', 'Physical attribute name'], // Ver1.0.20: 辞書ブロックにも (常真の条件、 1 行目に出すため)
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGED_DATE': ['変更日時', 'Changed at'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGED_BY': ['変更者ID', 'Changed by (ID)'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGED_USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGED_COLS': ['変更した列', 'Changed columns'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|SRC_FUNC_ID': ['発生元', 'Source'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|CHANGED_YM': ['年月', 'Month'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|SEQ_NO': ['属性NO', 'Attr. No'], // Ver1.0.13 (No.173)
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|ATTR_NM': ['物理属性名', 'Physical attribute name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|NOTE': ['備考', 'Note'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGED_DATE': ['変更日時', 'Changed at'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGED_BY': ['変更者ID', 'Changed by (ID)'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGED_USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGED_COLS': ['変更した列', 'Changed columns'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|SRC_FUNC_ID': ['発生元', 'Source'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|CHANGED_YM': ['年月', 'Month'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|CHANGED_DATE': ['変更日時', 'Changed at'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|CHANGED_USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|SRC_FUNC_ID': ['発生元', 'Source'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|CHANGED_COLS': ['変更した列', 'Changed columns'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|PROJECT_ID': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|DERIVE_RULE': ['導出ルール (値の算出方法)', 'Derivation rules (calculation)'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|HANDOVER_NOTE': ['ITへの申し送り', 'Handover to IT'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|REV_NO': ['照会中の版', 'Revision being viewed'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_CHANGED_DATE': ['変更日時', 'Changed at'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_CHANGED_USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_SRC_FUNC_ID': ['発生元', 'Source'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_CHANGED_COLS': ['変更した列', 'Changed columns'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_PROJECT_ID': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_DERIVE_RULE': ['導出ルール (値の算出方法)', 'Derivation rules (calculation)'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|PREV_HANDOVER_NOTE': ['ITへの申し送り', 'Handover to IT'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|SEQ_NO': ['属性NO', 'Attr. No'], // Ver1.0.13 (No.173)
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|ATTR_NM': ['物理属性名', 'Physical attribute name'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|NOTE': ['備考', 'Notes'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|CHANGED_COLS': ['変更した列', 'Changed columns'],
// Ver1.0.14: ブロック 4 = この版の定義域 (辞書側の補完)
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|DEF_COMMENT': ['コメント', 'Comment'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|CHANGED_COLS': ['変更した列', 'Changed columns'],
// Ver1.0.6: EDM の改訂履歴 (一覧。 EDM表示 = その版のプレビュー SVG のサムネイル)
'TLN_FUNC_DOC_EDM_HISTORY|0|EDM_CD': ['EDMコード', 'EDM code'],
'TLN_FUNC_DOC_EDM_HISTORY|0|EDM_NM': ['EDM表示名', 'EDM display name'],
'TLN_FUNC_DOC_EDM_HISTORY|0|REV_NO': ['版', 'Revision'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGE_KBN': ['変更種別', 'Change kind'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGED_DATE': ['変更日時', 'Changed at'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGED_BY': ['変更者ID', 'Changed by (ID)'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGED_USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_EDM_HISTORY|0|HIS_SVG_FILE': ['EDM表示', 'EDM view'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGE_NOTE': ['変更内容', 'Changes'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGED_COLS': ['変更した列', 'Changed columns'],
'TLN_FUNC_DOC_EDM_HISTORY|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_EDM_HISTORY|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_EDM_HISTORY|0|NOTE': ['備考', 'Notes'],
'TLN_FUNC_DOC_EDM_HISTORY|0|SRC_FUNC_ID': ['発生元', 'Source'],
'TLN_FUNC_DOC_EDM_HISTORY|0|CHANGED_YM': ['年月', 'Month'],
// Ver1.0.6: 改訂集計 (改訂履歴の集計。 ブロック 2 はグラフ)
'TLN_FUNC_DOC_HIS_STATS|0|CHANGED_YM': ['年月', 'Month'],
'TLN_FUNC_DOC_HIS_STATS|0|CHANGED_BY': ['変更者ID', 'Changed by (ID)'],
'TLN_FUNC_DOC_HIS_STATS|0|USER_NM': ['変更者', 'Changed by'],
'TLN_FUNC_DOC_HIS_STATS|0|BUMON_CD': ['部門', 'Department'],
'TLN_FUNC_DOC_HIS_STATS|0|BUMON_NM': ['部門名', 'Department name'],
'TLN_FUNC_DOC_HIS_STATS|0|DOM_I': ['辞書 新規', 'Dictionary added'],
'TLN_FUNC_DOC_HIS_STATS|0|DOM_U': ['辞書 更新', 'Dictionary updated'],
'TLN_FUNC_DOC_HIS_STATS|0|ATTR_I': ['物理属性 新規', 'Physical attribute added'], // Ver1.0.22 (No.232): 出荷 CSV の表示名は「物理属性 新規/更新」のまま (1.0.11 の改名は未出荷) → 対訳が食い違い英語に変わらなかった
'TLN_FUNC_DOC_HIS_STATS|0|ATTR_U': ['物理属性 更新', 'Physical attribute updated'],
'TLN_FUNC_DOC_HIS_STATS|0|EDM_I': ['EDM 新規', 'EDM added'],
'TLN_FUNC_DOC_HIS_STATS|0|EDM_U': ['EDM 更新', 'EDM updated'],
'TLN_FUNC_DOC_HIS_STATS|0|TOTAL_CNT': ['合計', 'Total'],
'TLN_FUNC_DOC_HIS_STATS|0|PERIOD_FROM': ['期間(自)', 'Period from'], // Ver1.0.13 (No.171)
'TLN_FUNC_DOC_HIS_STATS|0|PERIOD_TO': ['期間(至)', 'Period to'],
'TLN_FUNC_DOC_HIS_STATS|0|FILLED_CNT': ['記入した欄の数', 'Fields filled'], // Ver1.0.22 (No.178 案 A): 空 → 記入 の欄数
'TLN_FUNC_DOC_HIS_STATS|1|CHANGED_YM': ['年月', 'Month'],
'TLN_FUNC_DOC_HIS_STATS|1|DOM_I': ['辞書 新規', 'Dictionary added'],
'TLN_FUNC_DOC_HIS_STATS|1|DOM_U': ['辞書 更新', 'Dictionary updated'],
'TLN_FUNC_DOC_HIS_STATS|1|ATTR_I': ['物理属性 新規', 'Physical attribute added'],
'TLN_FUNC_DOC_HIS_STATS|1|ATTR_U': ['物理属性 更新', 'Physical attribute updated'],
'TLN_FUNC_DOC_HIS_STATS|1|EDM_I': ['EDM 新規', 'EDM added'],
'TLN_FUNC_DOC_HIS_STATS|1|EDM_U': ['EDM 更新', 'EDM updated'],
'TLN_FUNC_DOC_HIS_STATS|1|TOTAL_CNT': ['合計', 'Total'],
'TLN_FUNC_DOC_HIS_STATS|1|PERIOD_FROM': ['期間(自)', 'Period from'], // Ver1.0.13 (No.171)
'TLN_FUNC_DOC_HIS_STATS|1|PERIOD_TO': ['期間(至)', 'Period to'],
'TLN_FUNC_DOC_HIS_STATS|2|CHANGED_YM': ['年月', 'Month'],
'TLN_FUNC_DOC_HIS_STATS|2|BUMON_CD': ['部門', 'Department'],
'TLN_FUNC_DOC_HIS_STATS|2|BUMON_NM': ['部門名', 'Department name'],
'TLN_FUNC_DOC_HIS_STATS|2|USER_CNT': ['人数', 'Users'],
'TLN_FUNC_DOC_HIS_STATS|2|DOM_I': ['辞書 新規', 'Dictionary added'],
'TLN_FUNC_DOC_HIS_STATS|2|DOM_U': ['辞書 更新', 'Dictionary updated'],
'TLN_FUNC_DOC_HIS_STATS|2|ATTR_I': ['物理属性 新規', 'Physical attribute added'],
'TLN_FUNC_DOC_HIS_STATS|2|ATTR_U': ['物理属性 更新', 'Physical attribute updated'],
'TLN_FUNC_DOC_HIS_STATS|2|EDM_I': ['EDM 新規', 'EDM added'],
'TLN_FUNC_DOC_HIS_STATS|2|EDM_U': ['EDM 更新', 'EDM updated'],
'TLN_FUNC_DOC_HIS_STATS|2|TOTAL_CNT': ['合計', 'Total'],
'TLN_FUNC_DOC_HIS_STATS|2|PERIOD_FROM': ['期間(自)', 'Period from'], // Ver1.0.13 (No.171)
'TLN_FUNC_DOC_HIS_STATS|2|PERIOD_TO': ['期間(至)', 'Period to'],
'TLN_FUNC_DOC_HIS_STATS|2|FILLED_CNT': ['記入した欄の数', 'Fields filled'],
'TLN_FUNC_DOC|0|TLN_FUNC_DOC_OUT_FLG': ['出力対象', 'Output'],
'TLN_FUNC_DOC|0|FUNC_ID': ['機能ID', 'Function ID'],
'TLN_FUNC_DOC|0|FUNC_ID_IN': ['機能ID(IN)', 'Function ID (IN)'],
'TLN_FUNC_DOC|0|FUNC_ID_LIKE': ['機能ID(部分一致)', 'Function ID (partial)'], // Ver1.0.18: 部分一致 (INFIX) に統一
'TLN_FUNC_DOC|0|FUNC_NM': ['機能名', 'Function name'],
'TLN_FUNC_DOC|0|APP_KBN': ['アプリケーション区分', 'Application type'],
'TLN_FUNC_DOC|0|BG_L': ['業務分類(大)', 'Business category (L)'],
'TLN_FUNC_DOC|0|BG_M': ['業務分類(中)', 'Business category (M)'],
'TLN_FUNC_DOC|0|BG_S': ['業務分類(小)', 'Business category (S)'],
'TLN_FUNC_DOC|0|FUNC_OUTLINE': ['機能概要', 'Function outline'],
'TLN_FUNC_DOC|0|PROJECT_SEL': ['出力対象プロジェクト', 'Output project'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|ATTR_NM': ['物理属性名', 'Physical attribute name'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST|0|NOTE': ['備考', 'Notes'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_BULK|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|DERIVE_RULE': ['導出ルール', 'Derivation rules'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|HANDOVER_NOTE': ['ITへの申し送り', 'Handover to IT'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|ATTR_NM': ['物理属性名', 'Physical attribute name'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|NOTE': ['備考', 'Notes'],
// Ver1.0.3: 表示範囲 (3 択リスト) と プロジェクト条件 (ATTR_BULK は検索条件専用)
'TLN_FUNC_DOC_DOMAIN_BULK|0|REG_ONLY_FLG': ['表示範囲', 'Display range'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|HAS_ATTR': ['表示範囲', 'Display range'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|EDM_DECL_FLG': ['EDM属性の有無', 'EDM attribute set'], // 2026-10-09: 「EDM属性宣言の有無」から (行 = 物理属性ごと。 データドメインごとの条件 EDM_DECL_DOM_FLG は廃止)
// Ver1.0.22: EDM属性CSV一括登録
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|DEF_COMMENT': ['コメント', 'Comment'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|PROJECT_ID': ['プロジェクト名', 'Project name'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|PROJECT_ID': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|DERIVE_RULE': ['導出ルール (値の算出方法)', 'Derivation rules (calculation)'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|HANDOVER_NOTE': ['ITへの申し送り', 'Handover to IT'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|PROJECT_SRCH': ['プロジェクト', 'Project'], // Ver1.0.19: 検索条件 (共通行込み)
'TLN_FUNC_DOC_DOMAIN_LIST|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.19: 表示だけ (検索条件と重複させない)
'TLN_FUNC_DOC_DOMAIN_LIST|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|CNT': ['属性数', 'Attribute count'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|FILL_STS': ['記入状況', 'Fill status'],
// Ver1.0.16: ブロック 1 = 属性名で集約 (列挙の列は同じ COL_NAME で検索条件を共有) / ブロック 2 = エンティティ別
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|EDM_NM': ['EDM', 'EDM'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ENTITY_NM': ['エンティティ', 'Entity'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ATTR_NM': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|DOMAIN_NM': ['定義域', 'Domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|CUR_MAIN_NM': ['現在のデータドメイン', 'Current data domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|DISP_RANGE': ['表示範囲', 'Scope'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|DATA_TYPE': ['型', 'Type'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ENT_CNT': ['エンティティ数', 'Entities'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|DECL_CNT': ['宣言数', 'Declarations'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ENT_DECL_CNT': ['エンティティ別の宣言数', 'Per-entity declarations'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ENT_DOM_NMS': ['エンティティ別のデータドメイン', 'Per-entity data domains'], // Ver1.0.17
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ASSIGN_NM': ['データドメイン', 'Data domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|DEF_COMMENT': ['コメント', 'Comment'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|CUR_DOMAIN_CD': ['現在のデータドメインコード', 'Current data domain code'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.23 (No.270): 表示列 (サジェストの引数元)
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|ATTR_KEY': ['割当キー', 'Assign key'], // No.316: 隠し項目 (作業表のキー) だが Excel更新 のファイルの見出しに出る
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|EDM_NM': ['EDM', 'EDM'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|ENTITY_NM': ['エンティティ', 'Entity'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|ATTR_NM': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|DOMAIN_NM': ['定義域', 'Domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|CUR_MAIN_NM': ['現在のデータドメイン', 'Current data domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|DISP_RANGE': ['表示範囲', 'Scope'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|ENTITY_CD': ['エンティティ物理名', 'Entity physical name'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|ATTR_CD': ['属性物理名', 'Attribute physical name'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|DATA_TYPE': ['型', 'Type'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|ASSIGN_NM': ['データドメイン', 'Data domain'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|DEF_COMMENT': ['コメント', 'Comment'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.23 (No.270)
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|EDM_CD': ['EDMコード', 'EDM code'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|SEQ_NO': ['属性連番', 'Attribute no.'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|CUR_DOMAIN_CD': ['現在のデータドメインコード', 'Current data domain code'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|DECL_CNT': ['宣言数', 'Declarations'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|CREATED_USER_NM': ['作成者', 'Created by'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|CREATED_DATE': ['作成日', 'Created date'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|UPDATED_USER_NM': ['最終更新者', 'Last updated by'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|UPDATED_DATE': ['最終更新日', 'Last updated'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|DERIVE_RULE': ['導出ルール', 'Derivation rules'],
'TLN_FUNC_DOC_DOMAIN_LIST|0|TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
// Ver1.0.19: 記入画面の文脈表示 + 次の宿題 (隠し項目、 画面は LOAD JS が描く)
'TLN_FUNC_DOC_DOMAIN_EDIT|0|EDM_ATTRS': ['使われているEDM属性', 'EDM attributes in use'],
'TLN_FUNC_DOC_DOMAIN_EDIT|0|PHYS_ATTRS': ['物理属性', 'Physical attributes'],
// Ver1.0.18: 宿題一覧 (復活。 検索用 責任部門 / 表示列 責任部門名 は E0139 回避)
'TLN_FUNC_DOC_DOMAIN_TASKS|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|DISP_RANGE': ['表示範囲', 'Display range'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|RESP_DEPT_NM': ['責任部門名', 'Department name'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|BIZ_DEFN_STS': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|BIZ_RULE_STS': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|DERIVE_RULE_STS': ['導出ルール', 'Derivation rules'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|TACIT_STS': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|MISSING_CNT': ['未記入数', 'Unfilled count'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|EDM_ATTRS': ['使われているEDM属性', 'EDM attributes in use'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|UPDATED_USER_NM': ['最終更新者', 'Last updated by'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|UPDATED_DATE': ['最終更新日', 'Last updated'],
'TLN_FUNC_DOC_DOMAIN_TASKS|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|PROJECT_ID': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|CREATED_USER_NM': ['作成者', 'Created by'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|CREATED_DATE': ['作成日', 'Created date'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|UPDATED_USER_NM': ['最終更新者', 'Last updated by'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|UPDATED_DATE': ['最終更新日', 'Last updated'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|BIZ_DEFN': ['業務的定義', 'Business definition'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|BIZ_RULE': ['ビジネスルール', 'Business rules'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|DERIVE_RULE': ['導出ルール (値の算出方法)', 'Derivation rules (calculation)'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|TACIT_KNOWLEDGE': ['暗黙知・運用慣習', 'Tacit knowledge'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|HANDOVER_NOTE': ['ITへの申し送り', 'Handover to IT'],
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|MAIN_NM': ['データドメイン名称', 'Data domain name'],
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|DOMAIN_KIND': ['代表辞書種別', 'Primary kind'],
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|RESP_DEPT': ['責任部門', 'Department'],
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|PROJECT_SRCH': ['プロジェクト', 'Project'], // Ver1.0.23 (No.270): 共通行込みの条件 (割当のサジェストの絞り込み)
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.23 (No.270): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_DOMAIN_SEARCH|0|UPDATED_DATE': ['最終更新日', 'Last updated'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|SEQ_NO': ['属性NO', 'Attr. No'], // Ver1.0.13 (No.173): 隠していた NO を表示
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|ATTR_NM': ['物理属性名', 'Physical attribute name'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|NOTE': ['備考', 'Notes'],
// Ver1.0.14: ブロック 3 = EDM属性の定義域 (辞書側の補完。 モデル側は読み取り専用の参考表示)
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|DOMAIN_CD': ['データドメインコード', 'Data domain code'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|EDM_ATTR': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|EDM_DOMAIN_NM': ['モデルの定義域', 'Model domain'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|EDM_DATA_TYPE': ['モデルの型', 'Model type'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|DEF_COMMENT': ['コメント', 'Comment'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|EDM_DOMAIN_COMMENT': ['モデルの定義域コメント', 'Model domain comment'], // 2026-10-02 案 A: 属性のコメントと区別
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|EDM_ATTR_COMMENT': ['モデルの属性コメント', 'Model attribute comment'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|WARN_MARK': ['警告 (▲=他ドメイン重複)', 'Warning (▲=dup. in another domain)'], // Ver1.0.23 No.264
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|WARN_MARK': ['警告 (×=EDM未検出 ▲=他ドメイン重複)', 'Warning (×=not in EDM ▲=dup. in another domain)'],
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|PHYS_ATTRS': ['実装する物理属性', 'Implementing phys. attrs'], // 2026-10-08 No.287
'TLN_FUNC_DOC_EDM|0|EDM_CD': ['EDMコード', 'EDM code'],
'TLN_FUNC_DOC_EDM|0|EDM_NM': ['EDM表示名', 'EDM display name'],
'TLN_FUNC_DOC_EDM|0|PROJECT_ID': ['プロジェクト名', 'Project name'], // Ver1.0.22 (No.197): 表示だけ (検索条件は PROJECT_SRCH)
'TLN_FUNC_DOC_EDM|0|PROJECT_SRCH': ['プロジェクト', 'Project'],
'TLN_FUNC_DOC_EDM|0|SORT_NO': ['表示順', 'Display order'],
'TLN_FUNC_DOC_EDM|0|SVG_VIEW': ['EDM表示', 'EDM preview'],
'TLN_FUNC_DOC_EDM|0|SRC_FILE_READ': ['EDMデータ', 'EDM data'],
'TLN_FUNC_DOC_EDM|0|MODEL_FILE': ['EDMモデル', 'EDM model'],
'TLN_FUNC_DOC_EDM|0|SRC_FILE': ['EDMデータアップロード', 'EDM data upload'],
'TLN_FUNC_DOC_EDM|0|NOTE': ['備考', 'Notes'],
'TLN_FUNC_DOC_EDM|0|CREATED_DATE': ['作成日', 'Created date'],
'TLN_FUNC_DOC_EDM|0|UPDATED_DATE': ['最終更新日', 'Last updated'],
'TLN_FUNC_DOC_EDM|0|MODIFY_COUNT': ['更新数', 'Update count'],
'TLN_FUNC_DOC_EDM_ATTR_SUGGEST|0|ATTR_NM': ['EDM属性', 'EDM attribute'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|DB_NO': ['接続先', 'Connection'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|TBL_NM': ['物理テーブル名', 'Physical table name'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|COL_NM': ['物理項目名', 'Physical column name'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|LOGICAL_TBL_NM': ['論理テーブル名', 'Logical table name'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|LOGICAL_COL_NM': ['論理項目名', 'Logical column name'],
'TLN_FUNC_DOC_EXCL_MAINTE|0|NOTE': ['備考', 'Notes'],
'TLN_FUNC_DOC_EXCL_PICK|0|PICK_FLG': ['除外', 'Exclude'],
'TLN_FUNC_DOC_EXCL_PICK|0|FUNC_ID_IN': ['機能ID(IN)', 'Function ID (IN)'],
'TLN_FUNC_DOC_EXCL_PICK|0|FUNC_ID_LIKE': ['機能ID(部分一致)', 'Function ID (partial)'],
'TLN_FUNC_DOC_EXCL_PICK|0|FUNC_NM': ['機能名', 'Function name'],
'TLN_FUNC_DOC_EXCL_PICK|0|APP_KBN': ['アプリケーション区分', 'Application type'],
'TLN_FUNC_DOC_EXCL_PICK|0|BG_L': ['業務分類(大)', 'Business category (L)'],
'TLN_FUNC_DOC_EXCL_PICK|0|BG_M': ['業務分類(中)', 'Business category (M)'],
'TLN_FUNC_DOC_EXCL_PICK|0|BG_S': ['業務分類(小)', 'Business category (S)'],
'TLN_FUNC_DOC_EXCL_PICK|0|FUNC_OUTLINE': ['機能概要', 'Function outline'],
'TLN_FUNC_DOC_EXCL_PICK|0|DB_NO': ['接続先', 'Connection'],
'TLN_FUNC_DOC_EXCL_PICK|0|TBL_NM': ['物理テーブル名', 'Physical table name'],
'TLN_FUNC_DOC_EXCL_PICK|0|LOGICAL_TBL_NM_U': ['論理テーブル名(大小文字不問)', 'Logical table name (ignore case)'],
'TLN_FUNC_DOC_EXCL_PICK|0|COL_NM': ['物理項目名', 'Physical column name'],
'TLN_FUNC_DOC_EXCL_PICK|0|LOGICAL_COL_NM_U': ['論理項目名(大小文字不問)', 'Logical column name (ignore case)'],
'TLN_FUNC_DOC_EXCL_PICK|0|COL_TYPE': ['型', 'Type'],
'TLN_FUNC_DOC_EXCL_PICK|0|FUNC_CNT': ['参照機能数', 'Function count'],
'TLN_FUNC_DOC_EXCL_PICK|0|EXCL_STS_NM': ['除外状態', 'Exclusion status'],
'TLN_FUNC_DOC_EXCL_PICK|0|LOGICAL_TBL_NM': ['論理テーブル名', 'Logical table name'],
'TLN_FUNC_DOC_EXCL_PICK|0|LOGICAL_COL_NM': ['論理項目名', 'Logical column name'],
'TLN_FUNC_DOC_EXCL_PICK|1|PICK_FLG': ['除外', 'Exclude'],
'TLN_FUNC_DOC_EXCL_PICK|1|FUNC_ID_IN': ['機能ID(IN)', 'Function ID (IN)'],
'TLN_FUNC_DOC_EXCL_PICK|1|FUNC_ID_LIKE': ['機能ID(部分一致)', 'Function ID (partial)'],
'TLN_FUNC_DOC_EXCL_PICK|1|FUNC_NM': ['機能名', 'Function name'],
'TLN_FUNC_DOC_EXCL_PICK|1|APP_KBN': ['アプリケーション区分', 'Application type'],
'TLN_FUNC_DOC_EXCL_PICK|1|BG_L': ['業務分類(大)', 'Business category (L)'],
'TLN_FUNC_DOC_EXCL_PICK|1|BG_M': ['業務分類(中)', 'Business category (M)'],
'TLN_FUNC_DOC_EXCL_PICK|1|BG_S': ['業務分類(小)', 'Business category (S)'],
'TLN_FUNC_DOC_EXCL_PICK|1|FUNC_OUTLINE': ['機能概要', 'Function outline'],
'TLN_FUNC_DOC_EXCL_PICK|1|DB_NO': ['接続先', 'Connection'],
'TLN_FUNC_DOC_EXCL_PICK|1|COL_NM': ['物理項目名', 'Physical column name'],
'TLN_FUNC_DOC_EXCL_PICK|1|LOGICAL_COL_NM_U': ['論理項目名(大小文字不問)', 'Logical column name (ignore case)'],
'TLN_FUNC_DOC_EXCL_PICK|1|TBL_CNT': ['出現テーブル数', 'Table count'],
'TLN_FUNC_DOC_EXCL_PICK|1|EXCL_STS_NM': ['除外状態', 'Exclusion status'],
'TLN_FUNC_DOC_EXCL_PICK|1|LOGICAL_COL_NM': ['論理項目名', 'Logical column name'],
'TLN_FUNC_DOC_SETUP|0|DSP1': ['DBセットアップ', 'DB setup']
},
APP_VALUE: {
'TLN_FUNC_DOC|-1|EXECUTE_BTN_NAME_DISP_FORMULA': ['\'設計書出力\'', '\'Generate documents\''],
'TLN_FUNC_DOC_EXCL_PICK|-1|EXECUTE_BTN_NAME_DISP_FORMULA': ['\'除外登録\'', '\'Register exclusions\''],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|-1|EXECUTE_BTN_NAME_DISP_FORMULA': ['\'割当\'', '\'Assign\''],
'TLN_FUNC_DOC_EXCL_PICK|0|TAB_MENU_NAME': ['テーブル別', 'By table'],
'TLN_FUNC_DOC_EXCL_PICK|1|TAB_MENU_NAME': ['列名別', 'By column'],
'TLN_FUNC_DOC_DOMAIN_HISTORY|0|TAB_MENU_NAME': ['業務データ辞書', 'Dictionary'], // Ver1.0.20: 履歴一覧もタブ
'TLN_FUNC_DOC_DOMAIN_HISTORY|1|TAB_MENU_NAME': ['物理属性', 'Physical attributes'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|0|TAB_MENU_NAME': ['履歴の内容', 'Revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|1|TAB_MENU_NAME': ['前の版', 'Previous revision'],
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|2|TAB_MENU_NAME': ['物理属性', 'Physical attributes'], // Ver1.0.15
'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL|3|TAB_MENU_NAME': ['EDM属性', 'EDM attributes'], // Ver1.0.14 (Ver1.0.15: 定義域 → EDM属性)
'TLN_FUNC_DOC_DOMAIN_MAINTE|0|TAB_MENU_NAME': ['定義', 'Definition'], // Ver1.0.15: 単票もタブ (TALON はタブ名の無いブロックを隠す)
'TLN_FUNC_DOC_DOMAIN_MAINTE|1|TAB_MENU_NAME': ['物理属性', 'Physical attributes'], // Ver1.0.14: メンテナンスの下 2 ブロックはタブ (Ver1.0.15: 属性 → 物理属性)
'TLN_FUNC_DOC_DOMAIN_MAINTE|2|TAB_MENU_NAME': ['EDM属性', 'EDM attributes'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|TAB_MENU_NAME': ['属性名別', 'By attribute'], // Ver1.0.16: 割当の 2 タブ (Ver1.0.17: 属性名 → 属性名別)
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|1|TAB_MENU_NAME': ['エンティティ別', 'By entity']
},
BTN_KIND: {
'処理実行': ['処理実行', 'Execute'],
'業務データ辞書': ['業務データ辞書', 'Business data dictionary'],
'ドメイン新規作成': ['ドメイン新規作成', 'New domain'],
'詳細': ['詳細', 'Details'],
'データドメイン新規作成': ['データドメイン新規作成', 'New data domain'],
// Ver1.0.11: 業務データ辞書一覧の [書く] (→ 現場記入) / EDM属性割当の [辞書] (→ メンテナンス)
'書く': ['書く', 'Write'],
'辞書': ['辞書', 'Dictionary'],
// Ver1.0.11: 行ボタン「履歴」(業務データ辞書一覧 / EDM / 改訂集計) と「EDM履歴」(改訂集計)、 メンテナンス単票の [履歴]、
// EDM の機能ボタン [EDM履歴]。 ★行ボタンのラベルは ITEM_OPTN.KIND (ここ) と USES.KEY_CODE (USES_LABEL) の 2 か所に
// あり、 両方を同じ訳語にしないと en 状態のデザイナ再保存で USES 行が落ちる (verify_ui_language で 148→146 行の実例)
'履歴': ['履歴', 'History'],
'EDM履歴': ['EDM履歴', 'EDM history'],
'辞書履歴': ['辞書履歴', 'Dict. history'], // Ver1.0.13 (No.174): 改訂集計の行ボタン
'設計書一覧': ['設計書一覧', 'Document index'], // ★2026-10-08: 設計書出力の機能ボタン (他画面呼出 URL 指定 = サーバ保存の一覧)
'日本語に変換': ['日本語に変換', 'Convert to Japanese'],
'英語に変換': ['英語に変換', 'Convert to English'],
'メニュー登録': ['メニュー登録', 'Register menu']
},
// 明細行ボタンのラベル (TLN_M_GENERAL_USES.KEY_CODE)。
// ★対象は 利用者定義ボタン (OPTN='BUTTON') だけ。 TALON 標準の
// 参照 / 複写 / 削除 (OPTN='VIEW'/'COPY'/'DELETE') は TALON 自身が
// 所有するラベルで、 デザイナのブロック設定 [設定] (SAVE_BTN) が
// 既定値で再生成する (= 英訳しても保存 1 回で日本語へ戻る)。 実測:
// en 状態で roundtrip すると 'View'→'参照' 等の差分が必ず出る。
// フレームワークが再生成する値には製品から触れない。
USES_LABEL: {
// ★キーは BTN_KIND にも置く (行ボタンのラベルは ITEM_OPTN.KIND と USES.KEY_CODE の 2 か所。 tests/test_ui_lang_tables.py)。
// 旧 '参照' (View) は Ver1.0.11 で削除 — 利用者定義の行ボタン (OPTN='BUTTON') に「参照」は無く、 TALON 標準の 参照 (VIEW) は対象外
'詳細': ['詳細', 'Details'],
// Ver1.0.11: 業務データ辞書一覧の [書く] / EDM属性割当の [辞書]
'書く': ['書く', 'Write'],
'辞書': ['辞書', 'Dictionary'],
// Ver1.0.6: 改訂集計の行ボタン (利用者別 → 本人の履歴)
'履歴': ['履歴', 'History'],
'EDM履歴': ['EDM履歴', 'EDM history'],
'辞書履歴': ['辞書履歴', 'Dict. history']
},
// 項目グループ名 (TLN_M_GENERAL_ITEM.GROUP_NAME)。 ラベル文字列単位で
// TLN_FUNC_DOC% 全機能へ適用 (No.119: グループ見出しが英語に変換されなかった)
GROUP_NAME: {
'版の情報': ['版の情報', 'Revision info'],
'この版の内容': ['この版の内容', 'Contents of this revision'],
'前の版の情報': ['前の版の情報', 'Previous revision info'],
'前の版の内容': ['前の版の内容', 'Contents of previous revision'],
'ITとの受け渡し': ['ITとの受け渡し', 'IT handover'],
'意味の記述': ['意味の記述', 'Meaning description'],
'定義': ['定義', 'Definitions'],
'更新情報': ['更新情報', 'Update info']
},
HANYO_DSP1: {
'TLN_FUNC_DOC_HIS_KBN|I': ['新規', 'Added'],
'TLN_FUNC_DOC_HIS_KBN|U': ['更新', 'Updated'],
'TLN_FUNC_DOC_HIS_KBN|D': ['削除', 'Deleted'],
'TLN_FUNC_DOC_HIS_KBN|S': ['初期取込', 'Initial import'],
'TLN_FUNC_DOC_HIS_KBN|N': ['変更なし', 'Unchanged'],
'TLN_FUNC_DOC_APP_KBN|BAT': ['検索ボタン無し', 'No search button'],
'TLN_FUNC_DOC_APP_KBN|FREE': ['フリー検索条件', 'Free search condition'],
'TLN_FUNC_DOC_APP_KBN|STD': ['固定検索条件', 'Fixed search condition'],
'TLN_FUNC_DOC_APP_KBN|SUB': ['検索子画面', 'Sub search screen'],
'TLN_FUNC_DOC_DB_NO|0': ['0:主DB', '0:Primary DB'],
'TLN_FUNC_DOC_DB_NO|ALL': ['ALL:全接続先(串刺し)', 'ALL:All connections'],
'TLN_FUNC_DOC_DOMAIN_KIND|CATEGORY': ['カテゴリ', 'Category'],
'TLN_FUNC_DOC_DOMAIN_KIND|DATE': ['日付', 'Date'],
'TLN_FUNC_DOC_DOMAIN_KIND|IDENTIFIER': ['識別子', 'Identifier'],
'TLN_FUNC_DOC_DOMAIN_KIND|MONEY': ['金額', 'Amount'],
'TLN_FUNC_DOC_DOMAIN_KIND|OTHER': ['その他 (警告対象外)', 'Other (excluded from warnings)'],
'TLN_FUNC_DOC_DOMAIN_KIND|PENDING': ['(分類待ち — IT が設定)', '(Pending — IT will classify)'],
'TLN_FUNC_DOC_DOMAIN_KIND|QUANTITY': ['数量', 'Quantity'],
'TLN_FUNC_DOC_DOMAIN_KIND|TEXT': ['テキスト', 'Text'],
// Ver1.0.3: CSV 一括登録 2 機能の表示範囲 (リストボックス。 空 = すべて)
'TLN_FUNC_DOC_DOMAIN_BULK_DISP|1': ['登録されているドメインのみ表示する', 'Registered domains only'],
// Ver1.0.11: EDM属性割当の表示範囲 / 業務データ辞書一覧の記入状況 (★属性CSV一括登録の「EDM属性宣言(データドメイン)」は 2026-10-09 に廃止 = 汎用CD TLN_FUNC_DOC_DOMAIN_ATTR_EDM_DECL_DOM)
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN_DISP|1': ['未設定のみ', 'Unassigned only'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN_DISP|0': ['設定済みのみ', 'Assigned only'],
// (Ver1.0.19: TLN_FUNC_DOC_FILL_STS は廃止 — 一覧の記入状況も TLN_FUNC_DOC_DOMAIN_TASKS_DISP を共用)
// Ver1.0.18: 宿題一覧の表示範囲 (空 = すべて)
// Ver1.0.19: 4 区分のチェックボックス (行の値は排他的な 1 区分、 複数チェック = OR。 既定 2;3;4)
'TLN_FUNC_DOC_DOMAIN_TASKS_DISP|2': ['何も書いていない', 'Nothing written'],
'TLN_FUNC_DOC_DOMAIN_TASKS_DISP|3': ['業務的定義だけ書いてある', 'Only the business definition'],
'TLN_FUNC_DOC_DOMAIN_TASKS_DISP|4': ['業務的定義が空 (他は一部あり)', 'Business definition empty (others partly)'],
'TLN_FUNC_DOC_DOMAIN_TASKS_DISP|0': ['すべて記入済み', 'All filled'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK_DISP|0': ['属性が登録されているドメインのみ表示する', 'Domains with attributes only'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK_DISP|1': ['属性が登録されていないドメインのみ表示する', 'Domains without attributes only'],
'TLN_FUNC_DOC_DOMAIN_ATTR_EDM_DECL|0': ['あり', 'Declared'], // Ver1.0.20: 条件名 (EDM属性宣言の有無) が意味を持つので短く
'TLN_FUNC_DOC_DOMAIN_ATTR_EDM_DECL|1': ['なし', 'Not declared']
},
// メニューのフォルダ名 (TLN_M_AUTHORITY.FUNC_NM)。 ja/en 同値でも
// 対訳として持っておく (将来の改名で片方だけ直す事故を防ぐ)
MENU_GRP: {
'systemCOMMONWEAL': ['Commonweal', 'Commonweal']
},
// メニューの表示名 (TLN_M_FUNCTION.FUNC_NM)。
// ★ここが メニュー登録 (TFC.registerMenu / MENU_DEF) の登録名の正本でもある。
// 登録は環境の現在言語 (TFC.uiLang) 側の値を書き込む。
// ★★呼称は 3 系統 (機能名 FUNC_NM / メニュー MENU_NM / マニュアル表記) で
// 必ず一致させる (テスター指摘 No.137 / Ver0.62)。 規則は
// 機能名 = 'Commonweal' + 統一名 (英字で始まる名は 'Commonweal_' + 統一名)
// メニュー = 統一名 (= 機能名から製品名を取り除いたもの)
// マニュアル = 統一名
// en も同じ規則 (機能名 = 'Commonweal ' + 統一名の Title Case /
// メニュー = 統一名の Sentence case)。 旧版では「メニューは短い運用名」と
// していたが、 短くなっておらず利用者が画面を同定できないため撤廃した。
MENU_NM: {
'TLN_FUNC_DOC_DOMAIN_HISTORY': ['業務データ辞書履歴', 'Business data dictionary history'],
'TLN_FUNC_DOC_EDM_HISTORY': ['EDM履歴', 'EDM history'],
'TLN_FUNC_DOC_HIS_STATS': ['改訂集計', 'Revision summary'],
'TLN_FUNC_DOC': ['機能設計書出力', 'Function documents output'],
'TLN_FUNC_DOC_OUT_INDEX': ['設計書一覧', 'Design document index'], // ★2026-10-08: サーバ保存の一覧ページ (URL の行)
'TLN_FUNC_DOC_EDM': ['EDMメンテナンス', 'EDM maintenance'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN': ['EDM属性割当', 'EDM attribute assignment'],
'TLN_FUNC_DOC_DOMAIN_LIST': ['業務データ辞書一覧', 'Business data dictionary list'],
'TLN_FUNC_DOC_DOMAIN_TASKS': ['業務データ辞書宿題一覧', 'Business data dictionary tasks'], // Ver1.0.18 復活
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST': ['業務データ辞書属性一覧', 'Business data dictionary attributes'],
'TLN_FUNC_DOC_DOMAIN_MAINTE': ['業務データ辞書メンテナンス', 'Business data dictionary maintenance'],
'TLN_FUNC_DOC_EXCL_MAINTE': ['照合除外メンテナンス', 'Matching exclusion maintenance'],
'TLN_FUNC_DOC_EXCL_PICK': ['照合除外登録', 'Matching exclusion registration'],
// ★Ver1.0.2 追加分。 メニュー一覧の一番下に配置 (MENU_DEF.funcIds の末尾)
'TLN_FUNC_DOC_DOMAIN_BULK': ['業務データ辞書CSV一括登録', 'Business data dictionary CSV bulk registration'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK': ['物理属性CSV一括登録', 'Physical attribute CSV bulk registration'], // Ver1.0.22: 物理属性に戻す
'TLN_FUNC_DOC_DOMAIN_EDM_BULK': ['EDM属性CSV一括登録', 'EDM attribute CSV bulk registration']
},
// 改訂履歴 3 画面の BODY_SQL に直書きされた表示値 (「変更した列」の REPLACE 連鎖)。
// ★★2 値 CASE の両辺に入る訳語は **バイト長を揃える** (Oracle は両辺同長なら CHAR(n)、 違うと VARCHAR2(n) を
// 導出し、 デザイナが DATA_TYPE へ書き戻すため roundtrip 差分になる — Ver0.53 の実測)
SQL_LIT: {
// Ver1.0.6: 改訂履歴 3 画面の「変更した列」(物理列名 → 表示名の REPLACE) の表示名。 訳語は DISP_NAME と同じ
'データドメイン名称': ['データドメイン名称', 'Data domain name'], // Ver1.0.19: 表示名の統一 (データドメイン名 → 名称)
'代表辞書種別': ['代表辞書種別', 'Primary kind'], // Ver1.0.11: 辞書種別 → 代表辞書種別
'責任部門': ['責任部門', 'Department'],
'プロジェクト': ['プロジェクト', 'Project'],
'業務的定義': ['業務的定義', 'Business definition'],
'ビジネスルール': ['ビジネスルール', 'Business rules'],
'導出ルール': ['導出ルール', 'Derivation rules'],
'暗黙知・運用慣習': ['暗黙知・運用慣習', 'Tacit knowledge'],
'ITへの申し送り': ['ITへの申し送り', 'Handover to IT'],
'物理属性名': ['物理属性名', 'Physical attribute name'],
'EDM属性': ['EDM属性', 'EDM attribute'],
'備考': ['備考', 'Notes'],
'EDM表示名': ['EDM表示名', 'EDM display name'],
'表示順': ['表示順', 'Display order'],
'コメント': ['コメント', 'Comment'],
'EDMデータ': ['EDMデータ', 'EDM data'],
'属性': ['属性', 'Attributes'],
// Ver1.0.18: 宿題一覧の 済/未 (両辺 4 バイトで揃える — 'Todo'/'Done')
'未': ['未', 'Todo'],
'済': ['済', 'Done']
// Ver1.0.15: 変更した列 EDM_DEF は 'EDM属性'、 EDM属性の履歴の列 DEF_COMMENT は 'コメント' (上の対訳を共用。 Ver1.0.14 の 定義域 / 型 / 桁 / 定義域コメント は廃止)
},
// CSV 取込/出力ボタンのキャプション (TLN_M_GENERAL_ITEM_OPTN.COL_NAME — この
// FUNC_KBN (CSV_LOAD_BUTTON/CSV_OUT_BUTTON) は KIND ではなく COL_NAME が
// ボタンの表示文字列そのもの)。 キー = FUNC_ID|FUNC_SEQ|FUNC_KBN
// (TLN_FUNC_DOC_DOMAIN_BULK/_ATTR_BULK, Ver1.0.2 で導入)
// ★Ver1.0.22 (No.232): グラフの系列 = 凡例の文字列 (ITEM_OPTN COL_NAME='CHART_SERIES_BASE' の CHR_TEXT) と単位 (CHR5)。
// キー = 機能ID|ブロック|系列の列 (CHR1)。 CHR_TEXT は CLOB なので WHERE に書けない → 読んで比べて主キーで UPDATE
CHART_SERIES: {
'TLN_FUNC_DOC_HIS_STATS|1|DOM_I': ['辞書 新規', 'Dictionary added'],
'TLN_FUNC_DOC_HIS_STATS|1|DOM_U': ['辞書 更新', 'Dictionary updated'],
'TLN_FUNC_DOC_HIS_STATS|1|ATTR_I': ['物理属性 新規', 'Physical attribute added'],
'TLN_FUNC_DOC_HIS_STATS|1|ATTR_U': ['物理属性 更新', 'Physical attribute updated'],
'TLN_FUNC_DOC_HIS_STATS|1|EDM_I': ['EDM 新規', 'EDM added'],
'TLN_FUNC_DOC_HIS_STATS|1|EDM_U': ['EDM 更新', 'EDM updated']
},
CHART_UNIT: { // 系列の単位 (CHR5)
'TLN_FUNC_DOC_HIS_STATS|1': ['件数', 'Count']
},
CSV_BTN_LABEL: {
'TLN_FUNC_DOC_DOMAIN_BULK|0|CSV_LOAD_BUTTON': ['データドメインCSV取込', 'Import data domain CSV'],
'TLN_FUNC_DOC_DOMAIN_BULK|0|CSV_OUT_BUTTON': ['データドメインCSV出力', 'Export data domain CSV'],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|CSV_LOAD_BUTTON': ['物理属性CSV取込', 'Import physical attribute CSV'], // Ver1.0.22: 物理属性に戻す
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK|0|CSV_OUT_BUTTON': ['物理属性CSV出力', 'Export physical attribute CSV'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|CSV_LOAD_BUTTON': ['EDM属性CSV取込', 'Import EDM attribute CSV'],
'TLN_FUNC_DOC_DOMAIN_EDM_BULK|0|CSV_OUT_BUTTON': ['EDM属性CSV出力', 'Export EDM attribute CSV'],
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|CSV_LOAD_BUTTON': ['属性名別CSV取込', 'Import CSV (by attribute name)'], // Ver1.0.23 案 B (2026-10-09)。 No.317 (2026-10-21 案 A): 対象のタブをボタン名で示す
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN|0|CSV_OUT_BUTTON': ['属性名別CSV出力', 'Export CSV (by attribute name)']
}
};
// ============================================================
// EDM 属性宣言 (TLN_M_FUNC_DOMAIN_ATTR.EDM_ATTR) の共通ヘルパ (Ver0.51)
// 宣言記法: 属性名 (無修飾) または エンティティ名.属性名 (修飾)。
// カンマ区切り (半角/全角/読点) で複数宣言可。 全角ピリオドは修飾区切りとして受理。
// 設計書出力 (update-before) とメンテ画面の入力補助 (DOMAIN_MAINTE) の双方で使う。
// ============================================================
// ============================================================
// 文章中の URL のリンク化 (Ver1.0.8): 業務データ辞書の記述 (業務的定義 / ビジネスルール / 導出ルール / 暗黙知 / 物理属性の備考) を設計書に
// 出すとき、 http:// と https:// で始まる部分だけを <a> にする。 入力は生の文字列、 戻りはエスケープ済みの HTML。
// ★安全側の取り決め: 対象スキームは http / https だけ (javascript: / data: / file: 等はリンクにしない)。 href は属性エスケープ、
// 別タブで開き rel="noopener noreferrer" (開いた先から元の窓を操作させない、 設計書の URL (参照元) を相手に送らない)。
// URL は空白・引用符・山括弧・全角の記号 (。、「」()【】等) で止め、 末尾の句読点と閉じ括弧はリンクに含めない
// (「(…)」で囲まれた URL の閉じ括弧は対応する開き括弧があれば残す)。
// ============================================================
function _linkifyHtml(text) {
var str = TFC.s(text);
if (!str) return '';
var re = /https?:\/\/[^\s<>"'`\u2026\u3000-\u303F\uFF08\uFF09\uFF3B\uFF3D\uFF5B\uFF5D\uFF62\uFF63]+/g;
var out = '', last = 0, m;
while ((m = re.exec(str)) !== null) {
var url = m[0];
for (;;) { // 末尾の句読点・閉じ括弧を外す (括弧は対応が取れていれば残す)
var c = url.charAt(url.length - 1);
if (c === ')' || c === ']' || c === '}') {
var open = c === ')' ? '(' : (c === ']' ? '[' : '{');
if (url.split(open).length - 1 >= url.split(c).length - 1) break;
url = url.substring(0, url.length - 1);
} else if ('.,;:!?'.indexOf(c) >= 0) {
url = url.substring(0, url.length - 1);
} else break;
}
if (url.length <= 8) { re.lastIndex = m.index + m[0].length; continue; } // "https://" だけ等
out += TFC.escapeHtml(str.substring(last, m.index)) +
'<a href="' + TFC.escapeAttr(url) + '" class="tfc-ext-link" target="_blank" rel="noopener noreferrer" title="' + TFC.escapeAttr(url) + '">' +
TFC.escapeHtml(url) + '</a>';
last = m.index + url.length;
re.lastIndex = last;
}
return out + TFC.escapeHtml(str.substring(last));
}
TFC.linkifyHtml = _linkifyHtml;
TFC.parseEdmAttrDecl = function (raw) {
var out = [];
var s = TFC.s(raw);
if (!s) return out;
var parts = s.split(/[,,、]/);
for (var i = 0; i < parts.length; i++) {
var t = parts[i].replace(/\s+/g, ' ').replace(/^ | $/g, '');
if (t) out.push(t);
}
return out;
};
// ============================================================
// ER モデル層 (a5er の読み書き / ER 図の SVG / 他ツール形式の変換) は 共通JS TLN_FUNC_DOC_ER (TFE) に分離 (Ver1.0.7)。
// ここは委譲だけ。 TFE は同じスクリプト設定 (ライブラリ) で一緒に読み込む。 読み込み順に依存しないよう呼ぶたびに参照し、
// 無い / 古いときは文言 erlib.* で知らせる (tools/setup_er_library_refs.py が設定行にライブラリを足す)。
// ============================================================
var TFE_API_REQUIRED = 1;
function _tfe() {
if (typeof TFE === 'undefined' || !TFE) throw new Error(TFC.t('erlib.missing', TFC.detectLang()));
if ((TFE.API || 0) < TFE_API_REQUIRED) throw new Error(TFC.tf('erlib.old', TFC.detectLang(), [String(TFE.VERSION || '?'), String(TFE.API || 0), String(TFE_API_REQUIRED)]));
return TFE;
}
TFC.erLib = _tfe;
function _a5erNorm(s) { return _tfe().a5erNorm(s); } // 属性カタログの名前正規化
function _parseA5er(text) { return _tfe().parseA5erModel(text); }
function _a5erContentPages(model) { return _tfe().a5erContentPages(model); }
function _renderA5erToSvg(model, registry) { return _tfe().renderA5erToSvg(model, registry); }
TFC.parseA5er = function (text) { return _tfe().parseA5er(text); };
TFC.parseA5erModel = _parseA5er;
TFC.renderA5erToSvg = _renderA5erToSvg;
TFC.a5erContentPages = _a5erContentPages;
// ============================================================
// EDM 属性カタログ TLN_M_FUNC_EDM_ATTR_WK の洗い替え (Ver0.53)
//
// 登録済み EDM (.a5er) の中身を SQL で読めるテーブルにする。
// ★変化点は 「EDM の登録・差替・削除の確定」 だけ なので、 洗い替えの呼出も
// EDM メンテの確定後 (0S101) と セットアップ実行時 の 2 箇所だけにする。
// 辞書 (データドメイン・属性) の更新では EDM の中身は変わらないため呼ばない
// — 辞書との突合 (EDM 属性宣言) は画面の SQL (EDM属性割当 / 設計書出力の JS) が現在値で行う。
//
// 行種別 (ROW_KBN):
// 'E' = EDM 読取マーカー (SEQ_NO=0)。 .a5er として読めた EDM 1 件につき 1 行。
// 宿題一覧の 「読取れた EDM が 1 件以上あるか」 判定に使う
// 'A' = エンティティ属性行。 ENTITY_NM/CD + ATTR_NM/CD + DOMAIN_NM (★Ver1.0.11: 定義域名 = ツールのドメイン名。 参照でなければ空)
// + DATA_TYPE (DomainInfo の型 or 型の直書き) / DOMAIN_COMMENT。 型欄は辞書名として解釈しない。
// ('D' 行 = DomainInfo の定義行は Ver1.0.11 で廃止 — 読み手が無い)
// 'P' = 属性名 1 件 = 1 行の 「可視プロジェクト」 索引 (Ver0.61 / テスター指摘 No.134)。
// ATTR_NM + PJ_LIST (区切り文字連結のトークン列)。 EDM 属性サジェストの
// 候補元 (検索子画面) が この行だけを読み、 呼出元のプロジェクトで絞る。
// SEQ_NO=0 は 署名行 (ATTR_NM 空 / PJ_LIST=既知トークン列) — 再構築要否の判定用
//
// 確定トランザクション内で動く前提 (PreparedStatement 可・明示 commit 不要)。
// 識別子は未引用 = PG の小文字折りたたみで両対応。
// ============================================================
var EDM_ATTR_WK = 'TLN_M_FUNC_EDM_ATTR_WK';
var EDM_CAT_NM_MAX = 400; // ENTITY_NM / ATTR_NM / DOMAIN_NM / EDM_NM の列サイズ
var EDM_CAT_QNM_MAX = 801; // QUALIFIED_NM の列サイズ (400 + '.' + 400)
var EDM_CAT_PROJ_MAX = 200; // PROJECT_ID の列サイズ
var EDM_CAT_PJLIST_MAX = 2000; // PJ_LIST の列サイズ (可視プロジェクトのトークン列)
var EDM_CAT_TYPE_MAX = 400; // DATA_TYPE の列サイズ (Ver1.0.5)
var EDM_CAT_CMT_MAX = 4000; // DOMAIN_COMMENT の列サイズ (Ver1.0.5、 ユーザー指示で 4000)
var EDM_CAT_PJ_CD = '*'; // 'P' 行の EDM_CD (PK 用の固定値 — 特定 EDM に属さない行)
// ★SEQ_NO は数値列。 JS の数値をそのまま setObject すると Nashorn が Double に
// 変換し、 PostgreSQL の INTEGER 列で型不一致になり得るため Integer で束縛する
var _JInt = Java.type('java.lang.Integer');
function _edmCatCut(s, n) {
var v = TFC.s(s);
return (v.length > n) ? v.substring(0, n) : v;
}
// THUMBNAIL_UPLOAD_PATH の表示値 (= ファイル型項目の実体を置く物理ベースフォルダ)。 未設定は ''
function _edmThumbnailBase() {
try {
var pRows = TFC.selectPS(
'SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ? AND KEY_CODE = ?',
['TLN_GENERAL', 'THUMBNAIL_UPLOAD_PATH']);
if (pRows.length > 0) return TFC.s(pRows[0]['DSP1']);
} catch (eTh) { /* 未設定なら EDM を読めない */ }
return '';
}
// DB 値 "物理パス//元ファイル名" → .a5er の実パス (本体と同一規約)。 解決できなければ null
// TALON V6.2+ は「更新テーブル/項目/物理名」の相対パス入り、 旧仕様は葉の物理名だけ
function _edmSrcFullPath(basePath, srcVal) {
var v = TFC.s(srcVal);
if (!basePath || !v) return null;
var sepIdx = v.indexOf('//');
var physName = sepIdx >= 0 ? v.substring(0, sepIdx) : v;
if (!physName) return null;
return (physName.indexOf('/') >= 0 || physName.indexOf('\\') >= 0)
? (basePath + '/' + physName)
: (basePath + '/TLN_M_FUNC_EDM/SRC_FILE/' + physName);
}
// ---- 派生モデル (Ver1.0.7): 原本 SRC_FILE は残し、 製品が読む正規形 = MODEL_FILE (.a5er) ----
// 原本 SRC_FILE の値から派生モデルの計画: {ext, physName, leaf, model, convert}
// model = 期待する MODEL_FILE の値 ('' = 派生できない形式)、 convert = 変換が要る (true) / 同じファイルを指す (false = .a5er そのもの)
function _edmModelPlan(srcVal) {
var v = TFC.s(srcVal), sep = v.indexOf('//');
var physName = sep >= 0 ? v.substring(0, sep) : v, orig = sep >= 0 ? v.substring(sep + 2) : '';
var extM = /\.([A-Za-z0-9]+)$/.exec(physName), ext = extM ? extM[1].toLowerCase() : '';
var leaf = (orig || physName).replace(/^.*[\\\/]/, '');
var plan = { ext: ext, physName: physName, leaf: leaf, model: '', convert: false };
if (!physName) return plan;
if (ext === 'a5er') { plan.model = v; return plan; }
if (_EDM_UPLOAD_EXTS[ext]) {
plan.model = physName.replace(/\.[A-Za-z0-9]+$/, '.a5er') + '//' + leaf.replace(/\.[A-Za-z0-9]+$/, '') + '.a5er';
plan.convert = true;
}
return plan;
}
// 行が指すモデル (.a5er) の DB 値: MODEL_FILE、 無ければ .a5er を直接上げた SRC_FILE (MODEL_FILE 列の無い環境 / 未派生の行)
function _edmModelVal(row) {
var m = TFC.s(row['MODEL_FILE']);
if (m) return m;
var p = _edmModelPlan(row['SRC_FILE']);
return p.convert ? '' : p.model;
}
// 派生モデルを作り直すか (純関数、 tests/test_edm_models.py): 値が期待と違う / ファイルが無い / 原本の方が新しい (同じ行に上げ直すと TALON は
// 同じ物理名を付けるので値では気付けない — 2026-09-23 Visio の上げ直しで VARCHAR2 の古いモデルが残った) / 強制 (SETUP = 変換器の版上げの反映)
function _edmModelStale(curModel, expected, modelExists, srcMs, modelMs, force) {
if (force) return true;
if (TFC.s(curModel) !== TFC.s(expected)) return true;
if (!modelExists) return true;
return !!(srcMs && modelMs && srcMs > modelMs);
}
var _edmModelColCache = null;
function _edmHasModelCol() {
if (_edmModelColCache === null) {
try { _edmModelColCache = TFC.tableColumns('TLN_M_FUNC_EDM').indexOf('MODEL_FILE') >= 0; } catch (eMc) { _edmModelColCache = false; }
}
return _edmModelColCache;
}
// .a5er の実ファイルを読む (UTF-8 テキスト)。 無ければ null
function _edmCatReadSrc(basePath, srcVal) {
var fullPath = _edmSrcFullPath(basePath, srcVal);
if (!fullPath) return null;
try {
var Files = Java.type('java.nio.file.Files');
var Paths = Java.type('java.nio.file.Paths');
var JString = Java.type('java.lang.String');
var pth = Paths.get(fullPath);
if (!Files.exists(pth)) return null;
return new JString(Files.readAllBytes(pth), 'UTF-8') + '';
} catch (eRd) {
return null;
}
}
/**
* EDM 属性カタログ (TLN_M_FUNC_EDM_ATTR_WK) を洗い替える。
* @returns {edms: 読取れた EDM 数, attrs: 属性行数, domains: DomainInfo 行数}
*/
TFC.rebuildEdmAttrWk = function () {
// --- 1. EDM 台帳 + ファイル置き場 ---
var thumb = _edmThumbnailBase(); // 未設定なら EDM を読めない = カタログは空になる
var hasPj = false;
try { hasPj = TFC.tableColumns('TLN_M_FUNC_EDM').indexOf('PROJECT_ID') >= 0; } catch (eTc) {}
var edmRows = TFC.selectPS(
'SELECT EDM_CD,' + (hasPj ? ' PROJECT_ID,' : '') +
' EDM_NM, SRC_FILE' + (_edmHasModelCol() ? ', MODEL_FILE' : '') + ' FROM TLN_M_FUNC_EDM ORDER BY EDM_CD', []);
// --- 2. 先に全部パースする (途中で失敗しても既存カタログを壊さない) ---
var parsed = [];
for (var ei = 0; ei < edmRows.length; ei++) {
var er = edmRows[ei];
var edmCd = TFC.s(er['EDM_CD']);
if (!edmCd) continue;
var text = _edmCatReadSrc(thumb, _edmModelVal(er)); // Ver1.0.7: 派生モデル (.a5er)
if (!text) continue;
var doc = TFC.parseA5er(text);
if (doc == null) continue; // .a5er ではない (旧 drawio データ等)
parsed.push({
cd: edmCd,
nm: _edmCatCut(er['EDM_NM'], EDM_CAT_NM_MAX),
proj: _edmCatCut(_a5erNorm(TFC.s(er['PROJECT_ID'])), EDM_CAT_PROJ_MAX),
doc: doc
});
}
// --- 3. 洗い替え (DELETE + INSERT。 一意衝突は行単位スキップ) ---
TFC.updatePS('DELETE FROM ' + EDM_ATTR_WK, []);
// DATA_TYPE / DOMAIN_COMMENT は Ver1.0.5 追加列 — セットアップ未実行の旧 DB では列が無いので従来の列だけで書く
var hasExt = false, hasAcmt = false; // hasAcmt: ATTR_COMMENT (2026-10-02 案 A = 属性のコメント。 SETUP 未実行の DB では列が無い)
try { var wkCols = TFC.tableColumns(EDM_ATTR_WK); hasExt = wkCols.indexOf('DATA_TYPE') >= 0; hasAcmt = wkCols.indexOf('ATTR_COMMENT') >= 0; } catch (eTcx) {}
var INS = 'INSERT INTO ' + EDM_ATTR_WK +
' (EDM_CD, ROW_KBN, SEQ_NO, EDM_NM, PROJECT_ID, ENTITY_NM, ENTITY_CD,' +
' ATTR_NM, ATTR_CD, DOMAIN_NM, QUALIFIED_NM, PJ_LIST' + (hasExt ? ', DATA_TYPE, DOMAIN_COMMENT' : '') + (hasAcmt ? ', ATTR_COMMENT' : '') + ')' +
' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?' + (hasExt ? ', ?, ?' : '') + (hasAcmt ? ', ?' : '') + ')';
var nAttr = 0, nDom = 0;
function insRow(p, dtype, dcmt, acmt) {
if (p[4] === '') p[4] = null; // ★No.285 (2026-10-08): PROJECT_ID の空 (= 共通) は NULL で書く。 PostgreSQL / SQL Server / MySQL は '' を NULL にしないため、 画面 SQL の IS NULL / COALESCE (_ovl / PROJECT_SRCH) に当たらず、 共通 EDM の属性が割当に出ない・現在のデータドメインが空・辞書メンテナンスの × 印 になっていた
if (hasExt) p = p.concat([_edmCatCut(TFC.s(dtype), EDM_CAT_TYPE_MAX), _edmCatCut(TFC.s(dcmt), EDM_CAT_CMT_MAX)]);
if (hasAcmt) p = p.concat([_edmCatCut(TFC.s(acmt), EDM_CAT_CMT_MAX)]);
try { TFC.updatePS(INS, p); return true; }
catch (eIns) {
// 一意制約 (照合順序による同値衝突等) はスキップ — EXCL_PICK No.77 と同じ流儀
if (!/DOMA2004|unique|constraint|重複|PRIMARY|duplicate/i.test(String(eIns))) throw eIns;
return false;
}
}
for (var pi = 0; pi < parsed.length; pi++) {
var p = parsed[pi];
var seq = 0;
insRow([p.cd, 'E', _JInt.valueOf(0), p.nm, p.proj, '', '', '', '', '', '', '']);
for (var en = 0; en < p.doc.entities.length; en++) {
var ent = p.doc.entities[en];
var entNm = _edmCatCut(ent.nm, EDM_CAT_NM_MAX);
var entCd = _edmCatCut(ent.cd, EDM_CAT_NM_MAX);
for (var at = 0; at < ent.attrs.length; at++) {
var a = ent.attrs[at];
var attrNm = _edmCatCut(a.nm, EDM_CAT_NM_MAX);
// Ver1.0.11: DOMAIN_NM = ツールのドメイン名 (定義域名。 参照でなければ空)、 DATA_TYPE = DomainInfo の型 or 型の直書き、
// DOMAIN_COMMENT = DomainInfo のコメント。 型欄を辞書名として解釈しない
var dom = (TFC.s(a.domain).length > EDM_CAT_NM_MAX) ? '' : TFC.s(a.domain);
var qnm = (entNm && attrNm) ? _edmCatCut(entNm + '.' + attrNm, EDM_CAT_QNM_MAX) : '';
var aDef = a.userDomain ? p.doc.domainDefs[TFC.s(a.domain).toLowerCase()] : null;
var aType = aDef ? aDef.type : TFC.s(a.typeText);
var aCmt = aDef ? aDef.comment : '';
seq++;
if (insRow([p.cd, 'A', _JInt.valueOf(seq), p.nm, p.proj, entNm, entCd,
attrNm, _edmCatCut(a.cd, EDM_CAT_NM_MAX), dom, qnm, ''], aType, aCmt, a.comment)) nAttr++; // 案 A: 属性のコメント
}
}
}
// --- 4. 可視プロジェクト索引 ('P' 行) を作り直す (Ver0.61) ---
var nPj = 0;
try { nPj = TFC.rebuildEdmAttrPjRows(true, false).rows; } catch (ePj) {
try { TALON.getLogger().writeWarn('[TFC-EDM-CATALOG] 可視プロジェクト索引の再構築をスキップ: ' + ePj); } catch (ig3) {}
}
try {
TALON.getLogger().writeInfo('[TFC-EDM-CATALOG] EDM 属性カタログ洗い替え: EDM ' +
parsed.length + ' 件 / 属性 ' + nAttr + ' 行' +
' / 可視プロジェクト索引 ' + nPj + ' 行');
} catch (eLg) {}
return { edms: parsed.length, attrs: nAttr, domains: nDom, pjRows: nPj };
};
// ============================================================
// 可視プロジェクト索引 ('P' 行) — テスター指摘 No.134 (Ver0.61)
//
// EDM 属性サジェスト (検索子画面 TLN_FUNC_DOC_EDM_ATTR_SUGGEST) の候補を
// 「呼出元のデータドメインが属するプロジェクト」 で絞るための索引。
//
// ★なぜ事前展開するのか
// TALON はチェックボックス項目を引数にすると
// CONCAT(sep, CONCAT(列, sep)) LIKE '%sep+トークン+sep%' (選択トークンの OR)
// という 「トークンの重なり」 条件を **派生表の外側** に付ける
// (TLN_GENERALFREEDao#editSelectCondition)。 つまり
// ① 突合する列を SELECT リストへ射影しなければならない
// ② 「プロジェクト未設定の EDM = 全プロジェクトから見える」 を表すには
// 既知トークンを列側に並べておくしかない (全トークンの列挙が要る)
// ③ 候補は 1 行 = 1 オプション なので 属性名 1 件 = 1 行に畳む必要がある
// (畳まないと 「商品コード」 が EDM の数だけ候補に並ぶ)
// ②③ は文字列集約 (LISTAGG/STRING_AGG/GROUP_CONCAT) が要り 方言依存になる。
// さらにサジェストの子画面 SQL には ORDER BY を書けない (SQL Server の派生表制約)
// ので LISTAGG の WITHIN GROUP も使えない。 そこで JS 側で畳んで 'P' 行に持つ。
//
// ★陳腐化と再構築
// 'P' 行は 汎用CD TLN_FUNC_DOC_PROJECT の増減・辞書側 PROJECT_ID の変更でも
// 古くなる (新しいプロジェクトのドメインで候補が 0 件 = フェイルクローズになる)。
// そのため 「既知トークン列」 を署名行 (SEQ_NO=0) に持ち、 変化したときだけ
// 作り直す。 業務データ辞書メンテナンスの **検索前JS** から毎回呼んでも、 通常は
// SELECT 数本で終わる (冪等・低コスト)。 候補の取得は検索と同じ要求の中で
// 走るので、 検索前に追随させれば 「使う瞬間に必ず正しい」 が保証できる。
// ============================================================
// 属性名 → 可視プロジェクトのトークン列 を組み立てる (★純関数 — Node 単体回帰の対象)。
// attrRows : [{ ATTR_NM, PROJECT_ID }] ('A' 行。 PROJECT_ID = その EDM の所属)
// known : 既知プロジェクトトークンの配列 (昇順)
// sep : チェックボックスの区切り文字
// 戻り値 : [{ attrNm, pjList }] を attrNm 昇順で (= SEQ_NO が決定的になる)
// 規則: その属性を持つ EDM のうち 1 つでも 「プロジェクト未設定」 があれば
// 既知トークン全部 (= 誰から見ても可視)、 なければ所属トークンの和集合。
function _tfcEdmAttrPjRows(attrRows, known, sep) {
var s = String(sep || ';');
var allJoin = (known || []).join(s);
var map = {}, order = [];
for (var i = 0; i < (attrRows || []).length; i++) {
var r = attrRows[i] || {};
var nm = (r['ATTR_NM'] == null) ? '' : String(r['ATTR_NM']);
if (!nm) continue;
if (!map[nm]) { map[nm] = { seen: {}, toks: [], all: false }; order.push(nm); }
var pj = _tfcSplitProjectIds(r['PROJECT_ID'], s);
if (pj.length === 0) { map[nm].all = true; continue; }
for (var t = 0; t < pj.length; t++) {
if (!map[nm].seen[pj[t]]) { map[nm].seen[pj[t]] = 1; map[nm].toks.push(pj[t]); }
}
}
order.sort();
var out = [];
for (var o = 0; o < order.length; o++) {
var e = map[order[o]];
out.push({ attrNm: order[o], pjList: e.all ? allJoin : e.toks.sort().join(s) });
}
return out;
}
TFC.edmAttrPjRows = _tfcEdmAttrPjRows;
// EDM プレビュー SVG (ビューア埋め込み) の生成は TFE (Ver1.0.7 に分離)。 生成版の印 = TFE.EDM_PREVIEW_STAMP (_edmPreviewStamp() で参照)
function _tfcEdmPreviewSvg(svgText, title, lang) { return _tfe().edmPreviewSvg(svgText, title, lang); }
function _edmPreviewStamp() { return _tfe().EDM_PREVIEW_STAMP; }
TFC.edmPreviewSvg = _tfcEdmPreviewSvg;
// .a5er の実パス → 同名 .svg の実パス (拡張子 .a5er 以外は null = 対象外。 SELECT 式の REPLACE と同じ規則)
function _edmPreviewPathFor(srcFullPath) {
var p = TFC.s(srcFullPath);
if (!/\.a5er$/i.test(p)) return null;
return p.replace(/\.a5er$/i, '.svg');
}
/**
* 登録済み EDM のプレビュー SVG を (必要な行だけ) 生成する。 EDM メンテナンスの確定後 JS から呼ぶ。
* @param {Object} [opts] { force: true } で全行を作り直す
* @returns {generated, skipped, failed, noSrc, removed}
*/
TFC.rebuildEdmPreviewSvg = function (opts) {
var force = !!(opts && opts.force);
var res = { generated: 0, skipped: 0, failed: 0, noSrc: 0, removed: 0 };
var thumb = _edmThumbnailBase();
if (!thumb) { res.reason = 'THUMBNAIL_UPLOAD_PATH is not set'; return res; }
var Files = Java.type('java.nio.file.Files');
var Paths = Java.type('java.nio.file.Paths');
var JString = Java.type('java.lang.String');
var rows = TFC.selectPS('SELECT EDM_CD, EDM_NM, SRC_FILE' + (_edmHasModelCol() ? ', MODEL_FILE' : '') + ' FROM TLN_M_FUNC_EDM ORDER BY EDM_CD', []);
var lang = TFC.uiLang();
for (var i = 0; i < rows.length; i++) {
var r = rows[i];
var edmCd = TFC.s(r['EDM_CD']);
var srcPath = _edmSrcFullPath(thumb, _edmModelVal(r)); // Ver1.0.7: 派生モデル (.a5er) の隣に .svg
var svgPath = _edmPreviewPathFor(srcPath);
if (!srcPath || !svgPath) { res.noSrc++; continue; }
try {
var srcP = Paths.get(srcPath), svgP = Paths.get(svgPath);
if (!Files.exists(srcP)) { res.noSrc++; continue; }
if (!force && Files.exists(svgP)) {
var srcMs = Files.getLastModifiedTime(srcP).toMillis();
var svgMs = Files.getLastModifiedTime(svgP).toMillis();
if (svgMs >= srcMs) {
var head = new JString(Files.readAllBytes(svgP), 'UTF-8') + '';
if (head.substring(0, 300).indexOf(_edmPreviewStamp()) >= 0) { res.skipped++; continue; }
}
}
var text = new JString(Files.readAllBytes(srcP), 'UTF-8') + '';
var model = _parseA5er(text);
var out = '';
if (model.hasModel) {
var rend = _renderA5erToSvg(model, null);
out = _tfcEdmPreviewSvg(rend.svg, r['EDM_NM'], lang);
}
if (!out) {
if (Files.deleteIfExists(svgP)) res.removed++;
res.noSrc++;
continue;
}
Files.write(svgP, new JString(out).getBytes('UTF-8'));
res.generated++;
} catch (eRow) {
res.failed++;
try { TALON.getLogger().writeWarn('[TFC-EDM] preview svg failed EDM_CD=' + edmCd + ' (' + svgPath + '): ' + eRow); } catch (ig) {}
}
}
return res;
};
// ============================================================
// EDM モデルの派生 (Ver1.0.7): 原本 SRC_FILE は利用者が上げたまま残し、 製品が読む正規形 = 派生モデル MODEL_FILE (.a5er) を確定時に揃える。
// ・SRC_FILE が .a5er → MODEL_FILE = SRC_FILE と同じ値 (ファイルは 1 つ。 再アップロードで物理名が変われば追随する)。
// ・SRC_FILE が .edm (SI Object Browser ER) / .vsdx (Visio) / .asta (astah) → TFE (ER ライブラリ) で .a5er に
// 変換し、 原本と同じフォルダに同じ物理名 (拡張子だけ .a5er) で置いて MODEL_FILE = "物理名.a5er//元の名前.a5er"。 期待する値と一致して
// ファイルもあり、 原本の方が古ければ作り直さない (同じ行に上げ直すと TALON は同じ物理名を付けるので更新時刻で見る。 SETUP は force)。
// ・.svg / .drawio (旧) / 不明な拡張子 → MODEL_FILE は空 (読めない行)。 ★Ver1.0.22: DDL (.sql / .ddl / .txt) は廃止 (ユーザー決定 2026-09-29)。
// 旧形式以外の対応外の拡張子は details に kind='unsupported' を積み、 EDM の確定メッセージ edmUp.unsupported で知らせる。
// ・属性カタログ / プレビュー SVG / 改訂履歴 / 設計書出力は _edmModelVal(row) (MODEL_FILE、 無ければ .a5er の SRC_FILE) を読む。
// ・呼び出し = EDM 確定後 JS の先頭 (確定トランザクション内) と SETUP (列追加直後の既存行の一括派生)。 MODEL_FILE 列が無ければ何もしない
// (reason = 'no MODEL_FILE column')。 ZIP (.vsdx / .asta) の展開だけ Java (java.util.zip)。 Visio はページ XML の JSON、
// astah は EntityStore のバイト列 ({asta:1, name, bytes})、 .edm は UTF-8 (U+FFFD を含めば MS932) の文字列で TFE に渡す。
// ・戻り = {converted, linked, skipped, failed, details: [{edmCd, edmNm, from, to, kind, stats, warnings, ms} | {edmCd, edmNm, from, error} | {edmCd, edmNm, from, kind:'unsupported'}]}
// ============================================================
var _EDM_UPLOAD_EXTS = { edm: 1, vsdx: 1, asta: 1 }; // ★Ver1.0.22: sql / ddl / txt (DDL) は廃止 (ユーザー決定 2026-09-29)
var _EDM_LEGACY_EXTS = { svg: 1, drawio: 1 }; // 旧形式 (Ver1.0.3 以前の図) = 読めない行として黙って飛ばす (メッセージも出さない)
// ZIP の項目を取り出す (TFE の _vsdxUnzip と同じ戻り: 名前 → 文字列、 raw なら Uint8Array)
function _edmUnzipJava(bytes, wantRe, raw) {
var ZipInputStream = Java.type('java.util.zip.ZipInputStream');
var BAIS = Java.type('java.io.ByteArrayInputStream');
var BAOS = Java.type('java.io.ByteArrayOutputStream');
var JString = Java.type('java.lang.String');
var ByteArr = Java.type('byte[]');
var zis = new ZipInputStream(new BAIS(bytes)), out = {}, e, buf = new ByteArr(65536), n;
try {
while ((e = zis.getNextEntry()) != null) {
var name = String(e.getName());
if (!wantRe.test(name)) { zis.closeEntry(); continue; }
var bos = new BAOS();
while ((n = zis.read(buf, 0, buf.length)) > 0) bos.write(buf, 0, n);
var data = bos.toByteArray();
out[name] = raw ? new Uint8Array(Java.from(data)) : (new JString(data, 'UTF-8') + '');
zis.closeEntry();
}
} finally { zis.close(); }
return out;
}
function _edmBytesToText(bytes) {
var JString = Java.type('java.lang.String');
var t = new JString(bytes, 'UTF-8') + '';
if (t.indexOf('\uFFFD') >= 0) { try { t = new JString(bytes, 'MS932') + ''; } catch (eEnc) {} }
return t.replace(/^\uFEFF/, '');
}
// 原本のバイト列 → TFE.edmConvToA5er の入力 (拡張子で振り分け)
function _edmConvertInput(bytes, ext, leaf) {
if (ext === 'vsdx' || ext === 'asta') {
var xmls = _edmUnzipJava(bytes, /^visio\/(pages\/(pages\.xml|page\d+\.xml|_rels\/pages\.xml\.rels)|masters\/(masters\.xml|master\d+\.xml|_rels\/masters\.xml\.rels)|comments\.xml)$/, false); // ★No.209: マスターも / No.212: 校閲のコメントも
var b = _tfe().vsdxBundle(leaf, xmls);
if (b.pages.length) return JSON.stringify(b);
var rawz = _edmUnzipJava(bytes, /^EntityStore$/, true);
if (!rawz.EntityStore) throw new Error('neither Visio pages (visio/pages/*.xml) nor an astah EntityStore in the zip');
return { asta: 1, name: leaf.replace(/\.[^.]*$/, ''), bytes: rawz.EntityStore };
}
return _edmBytesToText(bytes);
}
TFC.ensureEdmModels = function (opts) {
var force = !!(opts && opts.force); // SETUP: 変換器の版上げを既存の派生モデルに反映するため他形式は作り直す (.a5er は値の複写だけ)
var res = { converted: 0, linked: 0, skipped: 0, failed: 0, details: [] };
_edmModelColCache = null; // SETUP は列を足した直後に呼ぶ
if (!_edmHasModelCol()) { res.reason = 'no MODEL_FILE column'; return res; }
var thumb = _edmThumbnailBase();
if (!thumb) { res.reason = 'THUMBNAIL_UPLOAD_PATH is not set'; return res; }
var Files = Java.type('java.nio.file.Files');
var Paths = Java.type('java.nio.file.Paths');
var JString = Java.type('java.lang.String');
var rows = TFC.selectPS('SELECT EDM_CD, EDM_NM, SRC_FILE, MODEL_FILE FROM TLN_M_FUNC_EDM ORDER BY EDM_CD', []);
for (var i = 0; i < rows.length; i++) {
var r = rows[i], edmCd = TFC.s(r['EDM_CD']), edmNm = TFC.s(r['EDM_NM']), curModel = TFC.s(r['MODEL_FILE']);
var plan = _edmModelPlan(r['SRC_FILE']);
if (!plan.model) { // 派生できない形式。 古い MODEL_FILE が残っていれば消す
if (curModel) TFC.updatePS('UPDATE TLN_M_FUNC_EDM SET MODEL_FILE = NULL WHERE EDM_CD = ?', [edmCd]);
res.skipped++;
// ★Ver1.0.22: 対応外の拡張子 (廃止した DDL .sql を含む。 旧形式 .svg / .drawio は黙って飛ばす) は確定メッセージで知らせる
if (plan.ext && !_EDM_LEGACY_EXTS[plan.ext]) res.details.push({ edmCd: edmCd, edmNm: edmNm, from: plan.leaf, kind: 'unsupported' });
continue;
}
var modelPath = _edmSrcFullPath(thumb, plan.model);
if (!plan.convert) { // .a5er そのもの: 値を写すだけ (ファイルは 1 つ)
if (curModel === plan.model) { res.skipped++; continue; }
TFC.updatePS('UPDATE TLN_M_FUNC_EDM SET MODEL_FILE = ? WHERE EDM_CD = ?', [plan.model, edmCd]);
res.linked++;
res.details.push({ edmCd: edmCd, edmNm: edmNm, from: plan.leaf, to: plan.leaf, kind: 'linked' });
continue;
}
var srcPath = _edmSrcFullPath(thumb, r['SRC_FILE']);
var modelExists = !!(modelPath && Files.exists(Paths.get(modelPath)));
var srcMs = 0, modelMs = 0;
try { if (srcPath && Files.exists(Paths.get(srcPath))) srcMs = Files.getLastModifiedTime(Paths.get(srcPath)).toMillis(); } catch (eT1) {}
try { if (modelExists) modelMs = Files.getLastModifiedTime(Paths.get(modelPath)).toMillis(); } catch (eT2) {}
if (!_edmModelStale(curModel, plan.model, modelExists, srcMs, modelMs, force)) { res.skipped++; continue; }
var d = { edmCd: edmCd, edmNm: edmNm, from: plan.leaf };
try {
if (!srcPath || !Files.exists(Paths.get(srcPath))) throw new Error('file not found: ' + srcPath);
var t0 = new Date().getTime();
var cv = _tfe().edmConvToA5er(_edmConvertInput(Files.readAllBytes(Paths.get(srcPath)), plan.ext, plan.leaf), {});
if (!cv.a5er) throw new Error('no entities');
Files.write(Paths.get(modelPath), new JString(cv.a5er).getBytes('UTF-8'));
TFC.updatePS('UPDATE TLN_M_FUNC_EDM SET MODEL_FILE = ? WHERE EDM_CD = ?', [plan.model, edmCd]);
d.kind = cv.kind; d.stats = cv.stats; d.warnings = cv.warnings; d.to = _edmOrigName(plan.model); d.ms = new Date().getTime() - t0;
res.converted++;
try { TALON.getLogger().writeInfo('[TFC-EDM] model derived EDM_CD=' + edmCd + ' ' + plan.leaf + ' -> ' + d.to + ' (' + cv.kind + ', ' + d.ms + ' ms) ' + JSON.stringify(cv.stats)); } catch (ig0) {}
} catch (eCv) {
d.error = String(eCv && eCv.message ? eCv.message : eCv);
res.failed++;
try { TALON.getLogger().writeWarn('[TFC-EDM] model derive failed EDM_CD=' + edmCd + ' (' + plan.leaf + '): ' + eCv); } catch (ig1) {}
}
res.details.push(d);
}
return res;
};
// ============================================================
// [[DOMAIN-HISTORY-MODULE-BEGIN]]
// 業務データ辞書 (TLN_M_FUNC_DOMAIN) と物理属性 (TLN_M_FUNC_DOMAIN_ATTR) の改訂履歴 (Ver1.0.6)
//
// 方式 = 「現在の行」と「履歴の最新版」を突き合わせ、 変わっていれば新しい版を追記する (差分検出)。
// - どの経路 (メンテナンス / 現場記入 / CSV 一括登録 / 直接 SQL) で書かれても拾える。
// 変更者と日時は行の UPDATED_BY / UPDATED_DATE から取るので、 経路に依らず正しく付く。
// - 削除 (物理削除) は 「最新版にあるが現在無い」 キーを 'D' の版として残す。 変更者は
// そのとき確定した利用者 (確定後フックから呼ばれた場合) か、 検出した利用者。
// - 呼び出し点: 辞書を書く 4 画面の確定後フック (UPDATE_AFTER)、 設計書出力の開始、 セットアップ
// (initial=true → 既存行を 'S' 初期取込として版 1 に)、 履歴 / 集計画面の検索前。
// 版番号 REV_NO はキーごとの連番 (削除後に同じコードで再登録すると次の版が 'I')。
// 比較は業務列だけ。 改行コードの差 (CRLF/LF) と末尾の空白は無視する (デザイナ再保存等で
// 中身が変わらないのに版が増えないように)。 空文字と NULL は同じ扱い。
// 履歴テーブルが無い環境 (セットアップ未実行) では何もしない (skipped=true)。
// ★確定トランザクション内で動く前提 (PreparedStatement 可・明示 commit 不要)。
// ★識別子は未引用 = PG の小文字折りたたみで両対応。 長文は Oracle のみ 4000 文字超を
// setCharacterStream で CLOB に書く (他 DB は setObject(String) で長さ制限なし)。
// ============================================================
var DOMAIN_HIS = 'TLN_M_FUNC_DOMAIN_HIS';
var DOMAIN_ATTR_HIS = 'TLN_M_FUNC_DOMAIN_ATTR_HIS';
var _HIS_DOM_COLS = ['PROJECT_ID', 'MAIN_NM', 'DOMAIN_KIND', 'BIZ_DEFN', 'BIZ_RULE', 'DERIVE_RULE',
'TACIT_KNOWLEDGE', 'RESP_DEPT', 'HANDOVER_NOTE'];
var _HIS_DOM_LONG = { BIZ_DEFN: 1, BIZ_RULE: 1, DERIVE_RULE: 1, TACIT_KNOWLEDGE: 1 };
var _HIS_ATTR_COLS = ['ATTR_NM', 'EDM_ATTR', 'NOTE'];
var _HIS_DEF_COLS = ['DEF_COMMENT']; // Ver1.0.14: 宣言行の業務列 (Ver1.0.15: 型・桁は廃止、 コメントだけ)
var _HIS_META_COLS = ['REV_NO', 'CHANGE_KBN', 'CHANGED_BY', 'CHANGED_DATE', 'CHANGED_YM',
'SRC_FUNC_ID', 'CHANGED_COLS', 'MODIFY_COUNT',
// TALON の基本項目 (Ver1.0.6、 ユーザー指摘): 履歴行を書いた日時 / 利用者 / 発生元機能。 追記専用なので UPDATED_ = CREATED_、 MODIFY_COUNT = 0
'CREATED_DATE', 'CREATED_BY', 'CREATED_PRG_NM', 'UPDATED_DATE', 'UPDATED_BY', 'UPDATED_PRG_NM'];
var _HIS_COLS_MAX = 400; // CHANGED_COLS の列サイズ
var _HIS_ORACLE_INLINE_MAX = 4000; // Oracle で setObject(String) のまま CLOB に入れられる上限
var _hisIsOracleCache = null;
// 値の正規化 (比較用): CLOB → 文字列、 NULL → ''、 CRLF/CR → LF、 末尾の空白を落とす
function _hisNormVal(v) {
var s = (typeof TFC.readClobVal === 'function') ? TFC.readClobVal(v) : (v == null ? '' : String(v));
return String(s == null ? '' : s).replace(/\r\n?/g, '\n').replace(/\s+$/, '');
}
// 業務列の差分 (列名の配列)
function _hisDiffCols(cols, a, b) {
var out = [];
for (var i = 0; i < cols.length; i++) {
if (_hisNormVal(a[cols[i]]) !== _hisNormVal(b[cols[i]])) out.push(cols[i]);
}
return out;
}
// 'YYYY-MM' (java.sql.Timestamp / java.util.Date / null → 現在)
// ============================================================
// ★Ver1.0.13 (No.192): EDM属性割当の本体 (Ver1.0.11 の 0S100 から移設)。 全体レベル (確定 = 画面の明細) と
// ブロックレベル (Excel更新 = 処理対象行ごと getTargetData) の両方から呼ぶ。
// targets = [{ line, nm, entNm, entCd, attrNm, curCd, proj, entOnly, defType, defLen, defComment, hasDef }] 戻り値 { created, linked, moved, defUpd } / 行エラーで null
// ★Ver1.0.14 第 2 段: 宣言 = 補完表 TLN_M_FUNC_DOMAIN_EDM_DEF の行 (属性行は物理属性名が必須で、 宣言だけの行は作らない)
// ============================================================
TFC.edmAttrAssignTarget = function (row, line, opts) {
var mode = (opts && opts.mode) || ''; /* Ver1.0.16: 'attr' = 属性名で集約した行 (宣言は属性名) / 'entity' = エンティティ別の行 (宣言は エンティティ.属性) / '' = Ver1.0.13 のチェック欄 ENT_ONLY */
function val(r, key) {
if (r == null) return '';
var v = null;
try { v = (typeof r.get === 'function') ? r.get(key) : r[key]; } catch (e1) {}
if (v == null) { var lk = key.toLowerCase(); try { v = (typeof r.get === 'function') ? r.get(lk) : r[lk]; } catch (e2) {} }
return (v == null) ? '' : String(v);
}
function trim(s) { return String(s == null ? '' : s).replace(/[\s ]+/g, ' ').replace(/^ | $/g, ''); }
/* Ver1.0.16: 画面の複数行入力は改行を CRLF で返すので LF に揃える (DB の値と同じでも差分扱いになって「コメント更新」が出ていた) */
function edge(s) { return String(s == null ? '' : s).replace(/\r\n?/g, '\n').replace(/^[\s ]+|[\s ]+$/g, ''); }
var nm = trim(val(row, 'ASSIGN_NM'));
var curCd = trim(val(row, 'CUR_DOMAIN_CD'));
/* Ver1.0.15: 宣言のコメント (辞書側。 定義域はモデルのものだけ)。 名前が空でも、 結び付け済みの行ならコメントだけの更新を受け付ける */
var defComment = edge(val(row, 'DEF_COMMENT'));
var hasDef = !!defComment;
var agg = (mode === 'attr');
/* ★No.266: 名前なし = 結び付け済みの行はコメントの更新 / 削除の候補 (DB の値と違うときだけ書く — 触っていない行は何もしない = No.267)。
結び付いていない行にコメントだけ入れても保存先の宣言が無い → 警告だけ (noDomain) */
if (!nm) {
if (!curCd) return hasDef ? { line: line, noDomain: true, attrNm: trim(val(row, 'ATTR_NM')) } : null;
if (!hasDef && mode === '') return null; /* Ver1.0.13 のチェック行方式 (旧) は従来どおり */
}
return { line: line, nm: nm, entNm: agg ? '' : trim(val(row, 'ENTITY_NM')), entCd: agg ? '' : trim(val(row, 'ENTITY_CD')), attrNm: trim(val(row, 'ATTR_NM')),
curCd: curCd, proj: trim(val(row, 'PROJECT_ID')), entOnly: (mode === 'entity') || (!agg && /1/.test(val(row, 'ENT_ONLY'))), agg: agg,
defComment: defComment, hasDef: hasDef, commentOnly: !nm,
entDeclCnt: agg ? (parseInt(val(row, 'ENT_DECL_CNT'), 10) || 0) : 0, entDomNms: agg ? trim(val(row, 'ENT_DOM_NMS')) : '' }; /* ★No.268 */
};
// 結び付け済みのデータドメイン cd の中で、 この EDM 属性に効いている宣言トークン (修飾 > 無修飾)。 宣言は補完表 (EDM_DEF) が正、 属性行の実装の対応も見る。 無ければ既定
function _assignCurToken(cd, tg, dflt) {
var qualU = _edmDefKey((tg.entNm || tg.entCd) + '.' + tg.attrNm);
var qualCdU = _edmDefKey(tg.entCd + '.' + tg.attrNm);
var bareU = _edmDefKey(tg.attrNm);
var toks = [], i, k;
var defs = TFC.selectPS('SELECT EDM_ATTR FROM TLN_M_FUNC_DOMAIN_EDM_DEF WHERE DOMAIN_CD = ?', [cd]);
for (i = 0; i < defs.length; i++) toks.push(_edmDefNormTok(defs[i]['EDM_ATTR']));
var rows = TFC.selectPS('SELECT EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND EDM_ATTR IS NOT NULL', [cd]);
for (i = 0; i < rows.length; i++) {
var rt = TFC.parseEdmAttrDecl(TFC.s(rows[i]['EDM_ATTR']));
for (k = 0; k < rt.length; k++) toks.push(_edmDefNormTok(rt[k]));
}
var bare = null;
for (i = 0; i < toks.length; i++) {
var u = _edmDefKey(toks[i]);
if (u === qualU || u === qualCdU) return toks[i];
if (u === bareU && bare == null) bare = toks[i];
}
return bare != null ? bare : dflt;
}
TFC.assignEdmAttrs = function (targets, lang) {
var EN = (lang === 'en');
var FUNC = 'TLN_FUNC_DOC_EDM_ATTR_ASSIGN';
var now = new (Java.type('java.sql.Timestamp'))(Java.type('java.lang.System').currentTimeMillis());
var by = (function () {
try { var ui = TALON.getUserInfoMap(); if (ui) { for (var k in ui) { if (/^(user_?id|login_?user_?id)$/i.test(k)) { var v = TFC.s(ui[k]); if (v) return v; } } } } catch (e) {}
return FUNC;
})();
var meta = { now: now, by: by, prg: FUNC };
/* 辞書種別の既定値 (汎用CD TLN_FUNC_DOC_DOMAIN_KIND の並び順の先頭) — 新規作成にだけ使う */
var defaultKind = '';
function kindDefault() {
if (defaultKind) return defaultKind;
try {
var kr = TFC.selectPS("SELECT KEY_CODE, DSP_SORT1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ? ORDER BY DSP_SORT1, KEY_CODE", ['TLN_FUNC_DOC_DOMAIN_KIND']);
if (kr.length > 0) defaultKind = TFC.s(kr[0]['KEY_CODE']);
} catch (eK) {}
return defaultKind || 'OTHER';
}
var hasPj = false;
try { hasPj = TFC.tableColumns('TLN_M_FUNC_DOMAIN').indexOf('PROJECT_ID') >= 0; } catch (eTc) {}
if (!TFC.edmDefAvailable()) { /* Ver1.0.14: 宣言の正本 = 補完表。 無い環境 (セットアップ未実行) では割当できない */
TALON.addErrorMsg(TFC.t('assign.noDefTable', lang));
TALON.setIsSuccess(false);
return null;
}
function normU(t) { return _edmDefKey(t); }
function nextSeq() { return Java.type('java.lang.Integer').valueOf(parseInt(TFC.nextSaibanCode('TLN_FUNC_DOC_DOMAIN_ATTR_SEQ'), 10)); }
function insertAttr(cd, attrNm, edmAttr, note) {
TFC.updatePS('INSERT INTO TLN_M_FUNC_DOMAIN_ATTR (DOMAIN_CD, SEQ_NO, ATTR_NM, EDM_ATTR, NOTE, ' +
'CREATED_DATE, CREATED_BY, CREATED_PRG_NM, UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)', [cd, nextSeq(), attrNm || null, edmAttr || null, note || null, now, by, FUNC, now, by, FUNC]);
}
/* 移す先に同じ物理属性名の行があれば、 その行の「実装する EDM 属性」にトークンを合流させる (同名の行を増やさない = Ver1.0.14 の一意性)。 合流したら true */
function mergeAttrTokens(cd, attrNm, addToks) {
if (!attrNm) return false;
var ex = TFC.selectPS('SELECT SEQ_NO, EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND UPPER(ATTR_NM) = ?', [cd, attrNm.toUpperCase()]);
if (!ex.length) return false;
var cur = TFC.parseEdmAttrDecl(TFC.s(ex[0]['EDM_ATTR'])), have = {}, i;
for (i = 0; i < cur.length; i++) have[normU(cur[i])] = 1;
for (i = 0; i < addToks.length; i++) if (!have[normU(addToks[i])]) { cur.push(addToks[i]); have[normU(addToks[i])] = 1; }
TFC.updatePS('UPDATE TLN_M_FUNC_DOMAIN_ATTR SET EDM_ATTR = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, MODIFY_COUNT = MODIFY_COUNT + 1 ' +
'WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [cur.length ? cur.join(', ') : null, now, by, FUNC, cd, ex[0]['SEQ_NO']]);
return true;
}
var cache = {}; /* 名前U|プロジェクト → DOMAIN_CD (同じ確定内で同じ名前は同じ辞書へ) */
var created = [], linked = 0, moved = 0, defUpd = 0, cleared = 0, touched = {};
/* ★No.266: データドメインが未設定の行のコメントは保存先が無い → 警告して除く */
var noDom = 0, kept = [];
for (var nd = 0; nd < targets.length; nd++) { if (targets[nd].noDomain) noDom++; else kept.push(targets[nd]); }
targets = kept;
if (noDom > 0) TALON.addWornMsg(TFC.tf('assign.commentNoDomain.warn', lang, [String(noDom)]));
/* ★No.266 / 267: 宣言のコメントは確定の前の DB の値と違うときだけ書く (データドメインごとに 1 回読んだ値 = この確定での比較の基準。 書いても読み直さない)。 空にしたら消す。 戻り 'upd' / 'clr' / '' */
var defsCache = {};
function defsOf(cd) {
if (!defsCache[cd]) defsCache[cd] = TFC.selectPS('SELECT EDM_ATTR, DEF_COMMENT FROM TLN_M_FUNC_DOMAIN_EDM_DEF WHERE DOMAIN_CD = ?', [cd]);
return defsCache[cd];
}
function curDefOf(cd, tg) { /* 結び付け済みのデータドメインの中で、 この EDM 属性に効いている宣言の行 (修飾 > 無修飾)。 無ければ null */
var qualU = normU((tg.entNm || tg.entCd) + '.' + tg.attrNm), qualCdU = normU(tg.entCd + '.' + tg.attrNm), bareU = normU(tg.attrNm), rows = defsOf(cd), bare = null;
for (var i = 0; i < rows.length; i++) { var u = normU(rows[i]['EDM_ATTR']); if (!tg.agg && (u === qualU || u === qualCdU)) return rows[i]; if (u === bareU && !bare) bare = rows[i]; }
return bare;
}
function writeComment(cd, tg) {
var cur = curDefOf(cd, tg);
if (!cur) return '';
var nl = function (v) { return TFC.s(v).replace(/\r\n?/g, '\n'); };
var dbv = nl(cur['DEF_COMMENT']), nv = nl(tg.defComment);
if (nv === dbv) return ''; /* ★確定の前の値 (キャッシュ) と比べる — 同じ宣言を見ている別のタブの行 (触っていない = 空のまま) が、 先に書いた値を消さないように */
if (!nv) { TFC.clearEdmDefComment(cd, TFC.s(cur['EDM_ATTR']), meta); return 'clr'; }
TFC.upsertEdmDef(cd, TFC.s(cur['EDM_ATTR']), tg, meta);
return 'upd';
}
for (var t = 0; t < targets.length; t++) {
var tg = targets[t];
var rowLbl = (EN ? 'Row ' : '') + tg.line + (EN ? '' : ' 行目');
if (!tg.attrNm || (!tg.agg && !tg.entNm && !tg.entCd)) { /* 集約行 (Ver1.0.16) は属性名だけでよい */
TALON.addErrorMsg(TFC.tf('assign.noEdmAttr', lang, [rowLbl]));
TALON.setIsSuccess(false);
return null;
}
var qual = tg.agg ? '' : (tg.entNm || tg.entCd) + '.' + tg.attrNm;
var tok = (!tg.agg && tg.entOnly) ? qual : tg.attrNm; /* Ver1.0.13: 既定は属性名 (全エンティティ)、 エンティティ別なら エンティティ.属性。 Ver1.0.16: 集約行は常に属性名 */
var cd;
if (!tg.nm) {
/* 名前なし = 結び付け済みのデータドメインのコメントの更新 / 削除 (DB と同じなら何もしない。 効いている宣言が無ければ作らない = No.267) */
cd = tg.curCd;
if (!cd) continue;
var wc = writeComment(cd, tg);
if (wc === 'upd') defUpd++; else if (wc === 'clr') cleared++;
if (wc) touched[cd] = 1;
continue;
}
var ck = tg.nm.toUpperCase() + '|' + tg.proj;
cd = cache[ck] || '';
if (!cd) {
var dup = TFC.checkDomainNameDup(tg.nm, null, tg.proj); /* blocking = プロジェクトが重なる同名 (= 同じ出力に同居する) */
if (dup.blocking.length > 1) {
TALON.addErrorMsg(TFC.tf('assign.ambiguous', lang, [rowLbl, tg.nm]));
TALON.setIsSuccess(false);
return null;
}
if (dup.blocking.length === 1) {
cd = dup.blocking[0].domainCd;
} else {
cd = TFC.nextSaibanCode('TLN_FUNC_DOC_DOMAIN_KEY');
TFC.updatePS('INSERT INTO TLN_M_FUNC_DOMAIN (DOMAIN_CD, MAIN_NM, DOMAIN_KIND' + (hasPj ? ', PROJECT_ID' : '') +
', CREATED_DATE, CREATED_BY, CREATED_PRG_NM, UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?' + (hasPj ? ', ?' : '') + ', ?, ?, ?, ?, ?, ?, 0)',
[cd, tg.nm, kindDefault()].concat(hasPj ? [tg.proj || null] : []).concat([now, by, FUNC, now, by, FUNC]));
created.push(tg.nm);
/* ★No.270: プロジェクトが重ならない同名のデータドメインがある → 別物として新しく作った (辞書メンテナンスの dom.dupMainNm.warn と同じ扱い) */
if (dup.disjoint.length) TALON.addMsg(TFC.tf('assign.newDisjoint.info', lang, [rowLbl, tg.nm, TFC.domainDupLabels(dup.disjoint, lang).join(EN ? ', ' : '、 ')]));
}
cache[ck] = cd;
}
if (tg.curCd && tg.curCd === cd) {
/* 既に同じデータドメインに結び付いている: コメントの更新 / 削除だけ (No.266) */
var wc2 = writeComment(cd, tg);
if (wc2 === 'upd') defUpd++; else if (wc2 === 'clr') cleared++;
if (wc2) touched[cd] = 1;
continue;
}
if (tg.curCd) {
/* 付け替え (Ver1.0.14): 古いデータドメイン側の宣言 (補完表の行) と、 この EDM 属性を実装する物理属性行を新しいデータドメインへ移す。
他の EDM 属性も実装する行はこの属性の分だけ新しい行に分ける。 移す先に同じ物理属性名の行があればそこへ合流する。
エンティティ別の付け替えは修飾宣言だけを対象にする (無修飾は他のエンティティに効いたまま残す) */
var matchU = tg.agg ? [normU(tg.attrNm)] /* Ver1.0.16: 集約行の付け替えは属性名の宣言だけ (エンティティ別の上書きは残す) */
: (tg.entOnly ? [normU(qual), normU(tg.entCd + '.' + tg.attrNm)] : [normU(qual), normU(tg.entCd + '.' + tg.attrNm), normU(tg.attrNm)]);
var oldDefs = TFC.selectPS('SELECT EDM_ATTR FROM TLN_M_FUNC_DOMAIN_EDM_DEF WHERE DOMAIN_CD = ?', [tg.curCd]);
for (var od = 0; od < oldDefs.length; od++) {
if (matchU.indexOf(normU(oldDefs[od]['EDM_ATTR'])) >= 0) TFC.moveEdmDefRow(tg.curCd, cd, TFC.s(oldDefs[od]['EDM_ATTR']), meta);
}
var old = TFC.selectPS('SELECT SEQ_NO, ATTR_NM, EDM_ATTR, NOTE FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND EDM_ATTR IS NOT NULL', [tg.curCd]);
for (var o = 0; o < old.length; o++) {
var toks = TFC.parseEdmAttrDecl(TFC.s(old[o]['EDM_ATTR'])), keep = [], mv = [];
for (var k = 0; k < toks.length; k++) (matchU.indexOf(normU(toks[k])) >= 0 ? mv : keep).push(toks[k]);
if (mv.length === 0) continue;
var seqNo = old[o]['SEQ_NO'], attrNm = TFC.s(old[o]['ATTR_NM']), note = TFC.s(old[o]['NOTE']);
if (keep.length === 0) {
if (mergeAttrTokens(cd, attrNm, mv)) {
TFC.updatePS('DELETE FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [tg.curCd, seqNo]);
} else {
/* 行ごと移す。 主キー (DOMAIN_CD, SEQ_NO) が新しい側で塞がっていれば作り直して古い行を消す (PG はエラーでトランザクションが壊れるので事前に確かめる) */
var clash = TFC.selectPS('SELECT COUNT(*) AS CNT FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [cd, seqNo]);
if (Number(TFC.s(clash[0]['CNT'])) > 0) {
insertAttr(cd, attrNm, mv.join(', '), note);
TFC.updatePS('DELETE FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [tg.curCd, seqNo]);
} else {
TFC.updatePS('UPDATE TLN_M_FUNC_DOMAIN_ATTR SET DOMAIN_CD = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [cd, now, by, FUNC, tg.curCd, seqNo]);
}
}
} else {
TFC.updatePS('UPDATE TLN_M_FUNC_DOMAIN_ATTR SET EDM_ATTR = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [keep.join(', '), now, by, FUNC, tg.curCd, seqNo]);
if (!mergeAttrTokens(cd, attrNm, mv)) insertAttr(cd, attrNm, mv.join(', '), note);
}
}
moved++;
touched[tg.curCd] = 1;
}
/* 宣言 = 補完表の行を新しい側に用意して (無ければ作る)、 入れた定義域を書く */
var wasNew = !_edmDefFind(cd, tok);
var changed = TFC.upsertEdmDef(cd, tok, tg, meta);
if (!wasNew && tg.hasDef && changed) defUpd++;
linked++;
touched[cd] = 1;
/* ★No.268: 属性名の宣言を変えても、 エンティティ別の宣言 (優先) は残る — 残ることを知らせる */
if (tg.agg && tg.entDeclCnt > 0) TALON.addWornMsg(TFC.tf('assign.entOverrideKept.warn', lang, [tg.attrNm, String(tg.entDeclCnt), tg.entDomNms || '']));
}
var tcds = [];
for (var tk in touched) if (touched.hasOwnProperty(tk)) tcds.push(tk);
if (tcds.length) TFC.syncEdmDefRows({ domainCds: tcds, srcFuncId: FUNC, now: now, by: by });
if (linked > 0) TALON.addMsg(TFC.tf('assign.done', lang, [String(linked)]));
if (created.length > 0) TALON.addMsg(TFC.tf('assign.created', lang, [created.join(EN ? ', ' : '、 ')]));
if (moved > 0) TALON.addMsg(TFC.tf('assign.moved', lang, [String(moved)]));
if (defUpd > 0) TALON.addMsg(TFC.tf('assign.defUpdated', lang, [String(defUpd)]));
if (cleared > 0) TALON.addMsg(TFC.tf('assign.defCleared', lang, [String(cleared)]));
if (linked === 0 && defUpd === 0 && cleared === 0 && created.length === 0) TALON.addMsg(TFC.tf('assign.done', lang, ['0']));
try { TALON.getLogger().writeInfo('[TFC-ASSIGN] linked=' + linked + ' created=' + created.length + ' moved=' + moved + ' defUpd=' + defUpd); } catch (ig) {}
return { created: created, linked: linked, moved: moved, defUpd: defUpd };
};
// ============================================================
// [[EDM-DEF-MODULE-BEGIN]]
// ★Ver1.0.14: 辞書側の EDM 属性の定義域 (補完) — TLN_M_FUNC_DOMAIN_EDM_DEF (ユーザー決定 2026-09-26)
// 宣言の表 (キー = データドメインコード + 宣言トークン) + 宣言のコメント (DEF_COMMENT)。
// ★Ver1.0.15: 型・桁の列 (DATA_TYPE / DATA_LEN) は廃止 — 定義域はモデルのものだけ (ユーザー決定 2026-09-26 夜。 定義域は 1 か所で定義して多くの属性が
// 共有するもので、 宣言ごとに型・桁を書かせると正規形が崩れる)。 新規作成の DDL から外し、 既存環境の列は手で落とす (セットアップに列削除は入れない)。
// - ★第 2 段 (同日): この表の行が「宣言」の正本 (物理属性名は必須に戻し、 宣言だけの属性行は無い)。 属性行の EDM_ATTR は「この物理属性が実装する EDM 属性」で、
// そのトークンは同期で補完表にも足す (実装があれば宣言もある)。 補完行は明示 (タブの行削除 / 付け替え) でしか消えない。
// モデルの値は写さない (写しは EDM を上げ直すと古くなる。 モデルは属性カタログ TLN_M_FUNC_EDM_ATTR_WK から生で読む)。
// - 定義域 (型・桁) はモデル (属性カタログ) だけ。 コメントは設計書の定義域欄の下に出す (Visio 等、 定義域の無いモデルはここに文章で書く)。
// - 書く画面: EDM属性割当 (コメントの入力欄) と 業務データ辞書メンテナンスの「EDM属性」タブ (更新テーブル = この表)。
// - 表が無い環境 (セットアップ未実行) では何もしない (edmDefAvailable = false)。
// ============================================================
var DOMAIN_EDM_DEF = 'TLN_M_FUNC_DOMAIN_EDM_DEF';
var DOMAIN_EDM_DEF_HIS = 'TLN_M_FUNC_DOMAIN_EDM_DEF_HIS';
var _edmDefAvailCache = null;
// 宣言トークンの正規化 (全角ピリオド → '.'、 空白の畳み込み、 前後の空白除去)。 比較はこれの UPPER
function _edmDefNormTok(t) {
return String(t == null ? '' : t).replace(/./g, '.').replace(/[\s ]+/g, ' ').replace(/^ | $/g, '');
}
TFC.normEdmDeclToken = _edmDefNormTok;
// ★No.276: 比較のキー = 正規化トークン → NFKC (全角 / 半角の同一視。 Node / ブラウザは String.normalize、 Nashorn は java.text.Normalizer) → 大文字。
// MySQL / SQL Server の照合は全角 / 半角を同一視して主キーを衝突させ、 Oracle / PostgreSQL は別の行にする → DB ではなく JS で比べる (No.262 と同じ)
function _edmDefKey(t) {
var s = _edmDefNormTok(t), done = false;
try { if (typeof s.normalize === 'function') { s = s.normalize('NFKC'); done = true; } } catch (e1) {}
if (!done) { try { var NZ = Java.type('java.text.Normalizer'), NF = Java.type('java.text.Normalizer$Form'); s = String(NZ.normalize(s, NF.NFKC)); } catch (e2) {} }
return s.replace(/[\s ]+/g, ' ').replace(/^ | $/g, '').toUpperCase();
}
TFC.edmDeclKey = _edmDefKey;
// 同期の計画 (純関数 — tests/test_edm_def_sync.py): 属性行の「実装する EDM 属性」(DOMAIN_CD / EDM_ATTR 生値、 カンマ区切り) に出てくるトークンで
// 補完表 (DOMAIN_CD / EDM_ATTR = 1 トークン) に無いものを足す (実装があれば宣言もある)。 消すのはデータドメインが無い行だけ (domCds、 null = 消さない)
function _edmDefPlan(declRows, defRows, domCds) {
var want = {}, have = {}, domSet = null, i, cd, key;
if (domCds) { domSet = {}; for (i = 0; i < domCds.length; i++) domSet[TFC.s(domCds[i])] = 1; }
for (i = 0; i < declRows.length; i++) {
cd = TFC.s(declRows[i]['DOMAIN_CD']);
if (!cd || (domSet && !domSet[cd])) continue;
var toks = TFC.parseEdmAttrDecl(TFC.s(declRows[i]['EDM_ATTR']));
for (var k = 0; k < toks.length; k++) {
var tok = _edmDefNormTok(toks[k]);
if (!tok) continue;
if (!want[cd]) want[cd] = {};
if (!want[cd][_edmDefKey(tok)]) want[cd][_edmDefKey(tok)] = tok;
}
}
for (i = 0; i < defRows.length; i++) {
cd = TFC.s(defRows[i]['DOMAIN_CD']);
key = _edmDefKey(defRows[i]['EDM_ATTR']);
if (!have[cd]) have[cd] = {};
have[cd][key] = TFC.s(defRows[i]['EDM_ATTR']);
}
var ins = [], del = [];
var cds = Object.keys(want).sort();
for (i = 0; i < cds.length; i++) {
var keys = Object.keys(want[cds[i]]).sort();
for (var w = 0; w < keys.length; w++) if (!(have[cds[i]] && have[cds[i]][keys[w]])) ins.push({ cd: cds[i], tok: want[cds[i]][keys[w]] });
}
// ★Ver1.0.14 第 2 段: 補完表の行 = 宣言の正本。 属性行の「実装する EDM 属性」に無くても消さない (消すのはタブで行削除 / 付け替え)。
// データドメインそのものが無い行だけ掃除する
var hcds = Object.keys(have).sort();
for (i = 0; i < hcds.length; i++) {
if (!(domSet && !domSet[hcds[i]])) continue;
var hk = Object.keys(have[hcds[i]]).sort();
for (var h = 0; h < hk.length; h++) del.push({ cd: hcds[i], edmAttr: have[hcds[i]][hk[h]] });
}
return { ins: ins, del: del };
}
TFC.edmDefAvailable = function () {
if (_edmDefAvailCache == null) {
try { TFC.tableColumns(DOMAIN_EDM_DEF); _edmDefAvailCache = true; } catch (e) { _edmDefAvailCache = false; }
}
return _edmDefAvailCache;
};
function _edmDefMeta(meta) {
meta = meta || {};
var now = meta.now || new (Java.type('java.sql.Timestamp'))(Java.type('java.lang.System').currentTimeMillis());
var by = meta.by;
if (!by) { try { by = TFC.s(TALON.getUserInfoMap().USER_ID); } catch (e) {} }
return { now: now, by: _edmCatCut(by || 'SYSTEM', 50), prg: _edmCatCut(TFC.s(meta.prg) || 'TFC', 50) };
}
// ★No.287 / 291 (ユーザー決定 2026-10-15 案 A): 宣言の綴りを EDM 側 (属性カタログ) に揃える計画 (純関数 — tests/test_edm_decl_canon.py)。
// 画面の SQL (辞書メンテナンスの × / 実装する物理属性、 割当の宣言数、 宿題一覧の使われている EDM 属性、 記入画面のチップ) は UPPER の完全一致で宣言と
// EDM 属性を突き合わせるため、 全角 / 半角だけ違う宣言 (NFKC では同じ = 確定前チェックと設計書は当たる) が画面の列では当たらなかった。 DB の照合順序には
// 頼れない (方言で成否が分かれる) ので、 保存のたび (= 同期 syncEdmDefRows の先頭) に宣言の綴りを EDM の綴りへ書き換える。 SETUP でも既存行を揃える。
// 規則: トークンのキー (_edmDefKey = NFKC + 大文字) が、 データドメインのプロジェクトと重なる EDM の「属性名」「エンティティ論理名.属性名」
// 「エンティティ物理名.属性名」のキーと一致すれば、 その綴りにする (カタログに綴りが混在していれば多い方 → 同数なら文字列順の先頭)。 カタログに無い
// トークンは同じデータドメインの宣言表の綴りに揃え (物理属性の EDM属性 → 宣言表)、 それも無ければそのまま。 大文字小文字の違いも EDM の綴りに揃える。
// cat = TFC.listEdmAttrCatalog() の形 { entities: [{ nm, cd, attrs: [..], projects: [..] }] } / defRows = [{ DOMAIN_CD, EDM_ATTR }] (宣言表) /
// declRows = [{ DOMAIN_CD, SEQ_NO, EDM_ATTR }] (物理属性の実装、 カンマ区切り可) / domProjects = { DOMAIN_CD: [プロジェクト..] (空 = 共通) }
// 戻り { defs: [{ cd, from, to, merge }], attrs: [{ cd, seqNo, from, to }] } (merge = 揃えた先の行が同じデータドメインに既にある → 合流)
function _edmDeclCanonPlan(cat, defRows, declRows, domProjects) {
var idx = {}, i, k, cd;
var addSpelling = function (key, spelling, projects) {
if (!key) return;
if (!idx[key]) idx[key] = [];
idx[key].push({ s: spelling, pj: projects || [] });
};
var ents = (cat && cat.entities) || [];
for (i = 0; i < ents.length; i++) {
var en = ents[i], pj = en.projects || [];
for (k = 0; k < (en.attrs || []).length; k++) {
var an = TFC.s(en.attrs[k]);
if (!an) continue;
addSpelling(_edmDefKey(an), an, pj);
if (en.nm) addSpelling(_edmDefKey(en.nm + '.' + an), en.nm + '.' + an, pj);
if (en.cd && en.cd !== en.nm) addSpelling(_edmDefKey(en.cd + '.' + an), en.cd + '.' + an, pj);
}
}
var pick = function (key, dcd) {
var cands = idx[key];
if (!cands) return '';
var dp = (domProjects && domProjects[dcd]) || [], cnt = {}, best = '', bestN = 0;
for (var c = 0; c < cands.length; c++) {
if (!_tfcProjectsOverlap(dp, cands[c].pj)) continue;
cnt[cands[c].s] = (cnt[cands[c].s] || 0) + 1;
}
var names = Object.keys(cnt).sort();
for (var n = 0; n < names.length; n++) if (cnt[names[n]] > bestN) { best = names[n]; bestN = cnt[names[n]]; }
return best;
};
var out = { defs: [], attrs: [] };
var spell = {}, taken = {}; /* spell[cd][key] = 宣言表の綴り (揃えた後) / taken[cd][綴り] = その綴りの行がある (既存 + 計画) */
for (i = 0; i < defRows.length; i++) {
cd = TFC.s(defRows[i]['DOMAIN_CD']);
var raw0 = TFC.s(defRows[i]['EDM_ATTR']);
if (!cd || !raw0) continue;
if (!taken[cd]) taken[cd] = {};
taken[cd][raw0] = 1;
}
for (i = 0; i < defRows.length; i++) {
cd = TFC.s(defRows[i]['DOMAIN_CD']);
var rawD = TFC.s(defRows[i]['EDM_ATTR']);
if (!cd || !rawD) continue;
var keyD = _edmDefKey(rawD), toD = pick(keyD, cd);
if (!spell[cd]) spell[cd] = {};
if (toD && toD !== rawD) {
out.defs.push({ cd: cd, from: rawD, to: toD, merge: !!taken[cd][toD] });
taken[cd][toD] = 1;
spell[cd][keyD] = toD;
} else if (!spell[cd][keyD]) {
spell[cd][keyD] = rawD;
}
}
for (i = 0; i < declRows.length; i++) {
cd = TFC.s(declRows[i]['DOMAIN_CD']);
var rawA = TFC.s(declRows[i]['EDM_ATTR']);
if (!cd || !rawA) continue;
var parts = rawA.split(/([,,、])/), changed = false;
for (k = 0; k < parts.length; k += 2) {
var t = parts[k].replace(/\s+/g, ' ').replace(/^ | $/g, '');
if (!t) continue;
var keyA = _edmDefKey(t), toA = pick(keyA, cd) || (spell[cd] && spell[cd][keyA]) || '';
if (!toA || toA === t) continue;
parts[k] = (parts[k].indexOf(t) >= 0) ? parts[k].replace(t, toA) : toA;
changed = true;
}
if (changed) out.attrs.push({ cd: cd, seqNo: declRows[i]['SEQ_NO'], from: rawA, to: parts.join('') });
}
return out;
}
/**
* ★No.287 / 291: 宣言の綴りを EDM 側に揃える (計画 = _edmDeclCanonPlan、 書き込みはここ)。 呼び出し点 = syncEdmDefRows の先頭 (辞書を書く画面の確定後 / EDM属性CSV一括登録 /
* 設計書出力の追いつき / SETUP)。 揃えた先の行が同じデータドメインに既にあれば合流 (コメントが空なら写して、 元の行を消す)。
* @param opts { domainCds (省略 = 全部), now, by, srcFuncId, lang (あれば利用者へ通知) }
* @return { defs, attrs, merged, items: ['from → to', ..] }
*/
TFC.canonEdmDeclSpelling = function (opts) {
opts = opts || {};
var res = { defs: 0, attrs: 0, merged: 0, items: [] };
if (!TFC.edmDefAvailable()) return res;
var cat = TFC.listEdmAttrCatalog();
var cds = (opts.domainCds && opts.domainCds.length) ? opts.domainCds : null;
var ph = cds ? cds.map(function () { return '?'; }).join(',') : '';
var where = cds ? ' WHERE DOMAIN_CD IN (' + ph + ')' : '';
var prm = cds ? cds : [];
var defRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR FROM ' + DOMAIN_EDM_DEF + where, prm);
var declRows = TFC.selectPS('SELECT DOMAIN_CD, SEQ_NO, EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR' + (cds ? where + ' AND' : ' WHERE') + ' EDM_ATTR IS NOT NULL', prm);
var domRows = TFC.selectPS('SELECT DOMAIN_CD, PROJECT_ID FROM TLN_M_FUNC_DOMAIN' + where, prm);
var domProjects = {};
for (var d = 0; d < domRows.length; d++) domProjects[TFC.s(domRows[d]['DOMAIN_CD'])] = _tfcSplitProjectIds(TFC.s(domRows[d]['PROJECT_ID']));
var plan = _edmDeclCanonPlan(cat, defRows, declRows, domProjects);
if (!plan.defs.length && !plan.attrs.length) return res;
var m = _edmDefMeta({ now: opts.now, by: opts.by, prg: opts.srcFuncId });
var i;
for (i = 0; i < plan.defs.length; i++) {
var p = plan.defs[i];
/* ★No.323: 合流するかは計画 (JS、 綴りの完全一致 = p.merge) で決める。 SQL の EDM_ATTR = ? で探すと、 SQL Server / MySQL の
照合順序が大文字小文字 (と全角半角) を同一視するため、 揃える前の行そのもの (test) が揃えた先 (TEST) として当たり、
「既にある → 合流」で元の行を消して宣言が無くなっていた。 同一視する DB では 2 つの綴りが同じ主キーに同居できないので、
合流が要るのは Oracle / PostgreSQL で両方の行が実在するときだけ = JS の完全一致で足りる。 */
if (p.merge) { /* 合流: 揃えた先の行が既にある → コメントが空なら写して、 元の行を消す */
var dst = TFC.selectPS('SELECT EDM_ATTR, DEF_COMMENT FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [p.cd, p.to]);
var src = TFC.selectPS('SELECT DEF_COMMENT FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [p.cd, p.from]);
var sc = src.length ? TFC.s(src[0]['DEF_COMMENT']) : '';
if (sc && dst.length && !TFC.s(dst[0]['DEF_COMMENT'])) {
TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET DEF_COMMENT = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [sc, m.now, m.by, m.prg, p.cd, p.to]);
}
TFC.updatePS('DELETE FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [p.cd, p.from]);
res.merged++;
} else {
TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET EDM_ATTR = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [p.to, m.now, m.by, m.prg, p.cd, p.from]);
}
res.defs++;
res.items.push(p.from + ' → ' + p.to);
}
for (i = 0; i < plan.attrs.length; i++) {
var a = plan.attrs[i];
TFC.updatePS('UPDATE TLN_M_FUNC_DOMAIN_ATTR SET EDM_ATTR = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND SEQ_NO = ?', [a.to, m.now, m.by, m.prg, a.cd, a.seqNo]);
res.attrs++;
res.items.push(a.from + ' → ' + a.to);
}
if (opts.lang && res.items.length) {
try { TALON.addMsg(TFC.tf('mainte.declCanon.msg', opts.lang, [String(res.defs + res.attrs), res.items.join(opts.lang === 'en' ? ', ' : '、 ')])); } catch (eM) {}
}
try { TALON.getLogger().writeInfo('[TFC-DOMAIN] 宣言の綴りを EDM に揃えた: ' + JSON.stringify(res)); } catch (eL) {}
return res;
};
/**
* 宣言と補完行を同期する (宣言が増えれば空の補完行を作り、 消えれば補完行を消す)。
* @param opts { domainCds: [DOMAIN_CD..] (省略 = 全データドメイン。 実在しないデータドメインの補完行も消す), srcFuncId, now, by, lang (あれば綴り揃えを利用者へ通知) }
* @return { ins, del, skipped, canon (★No.287 / 291: 宣言の綴りを EDM 側に揃えた件数 = TFC.canonEdmDeclSpelling の戻り) }
*/
TFC.syncEdmDefRows = function (opts) {
opts = opts || {};
var res = { ins: 0, del: 0, skipped: false };
if (!TFC.edmDefAvailable()) { res.skipped = true; return res; }
var cds = (opts.domainCds && opts.domainCds.length) ? opts.domainCds : null;
/* ★No.287 / 291 (2026-10-15 案 A): 先に宣言の綴りを EDM 側に揃える (失敗しても同期は続ける) */
try { res.canon = TFC.canonEdmDeclSpelling({ domainCds: cds, now: opts.now, by: opts.by, srcFuncId: opts.srcFuncId, lang: opts.lang }); }
catch (eCn) { try { TALON.getLogger().writeWarn('[TFC-DOMAIN] 宣言の綴り揃えに失敗 (同期は続行): ' + eCn); } catch (ig0) {} }
var declRows, defRows, domRows, ph = cds ? cds.map(function () { return '?'; }).join(',') : '';
if (cds) {
declRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR WHERE EDM_ATTR IS NOT NULL AND DOMAIN_CD IN (' + ph + ')', cds);
defRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD IN (' + ph + ')', cds);
domRows = TFC.selectPS('SELECT DOMAIN_CD FROM TLN_M_FUNC_DOMAIN WHERE DOMAIN_CD IN (' + ph + ')', cds);
} else {
declRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR WHERE EDM_ATTR IS NOT NULL', []);
defRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR FROM ' + DOMAIN_EDM_DEF, []);
domRows = TFC.selectPS('SELECT DOMAIN_CD FROM TLN_M_FUNC_DOMAIN', []);
}
var domCds = [];
for (var d = 0; d < domRows.length; d++) domCds.push(TFC.s(domRows[d]['DOMAIN_CD']));
var plan = _edmDefPlan(declRows, defRows, domCds);
var m = _edmDefMeta({ now: opts.now, by: opts.by, prg: opts.srcFuncId });
for (var i = 0; i < plan.ins.length; i++) {
TFC.updatePS('INSERT INTO ' + DOMAIN_EDM_DEF + ' (DOMAIN_CD, EDM_ATTR, DEF_COMMENT, ' +
'CREATED_DATE, CREATED_BY, CREATED_PRG_NM, UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, NULL, ?, ?, ?, ?, ?, ?, 0)', [plan.ins[i].cd, plan.ins[i].tok, m.now, m.by, m.prg, m.now, m.by, m.prg]);
res.ins++;
}
for (var j = 0; j < plan.del.length; j++) {
res.del += TFC.updatePS('DELETE FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [plan.del[j].cd, plan.del[j].edmAttr]);
}
return res;
};
function _edmDefFind(cd, tok) { /* ★No.276: 全角 / 半角・大文字小文字を同一視して JS で探す (DB の照合に依存しない) */
var key = _edmDefKey(tok);
if (!cd || !key) return null;
var rows = TFC.selectPS('SELECT EDM_ATTR, DEF_COMMENT FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ?', [cd]);
for (var i = 0; i < rows.length; i++) if (_edmDefKey(rows[i]['EDM_ATTR']) === key) return rows[i];
return null;
}
/**
* 宣言行のコメントを書く (行が無ければ作る)。 vals = { defComment } — 空なら既存値を残す (消すのはメンテナンスのタブで)。
* @return true = 書いた / false = 変更なし
*/
TFC.upsertEdmDef = function (cd, tok, vals, meta) {
if (!TFC.edmDefAvailable()) return false;
var m = _edmDefMeta(meta);
var t = _edmDefNormTok(tok);
if (!cd || !t) return false;
var cur = _edmDefFind(cd, t);
var nl = function (v) { return TFC.s(v).replace(/\r\n?/g, '\n'); }; /* Ver1.0.16: 改行は LF に揃えて比べる・書く */
var nc = nl(vals.defComment) || (cur ? nl(cur['DEF_COMMENT']) : '');
if (cur) {
if (nc === nl(cur['DEF_COMMENT'])) return false;
TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET DEF_COMMENT = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND EDM_ATTR = ?',
[nc || null, m.now, m.by, m.prg, cd, TFC.s(cur['EDM_ATTR'])]);
return true;
}
TFC.updatePS('INSERT INTO ' + DOMAIN_EDM_DEF + ' (DOMAIN_CD, EDM_ATTR, DEF_COMMENT, ' +
'CREATED_DATE, CREATED_BY, CREATED_PRG_NM, UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)', [cd, t, nc || null, m.now, m.by, m.prg, m.now, m.by, m.prg]);
return true;
};
/** ★No.266: 宣言のコメントを消す (EDM属性割当で入力欄を空にして [割当]) */
TFC.clearEdmDefComment = function (cd, edmAttrRaw, meta) {
if (!TFC.edmDefAvailable()) return false;
var m = _edmDefMeta(meta);
return TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET DEF_COMMENT = NULL, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [m.now, m.by, m.prg, cd, edmAttrRaw]) > 0;
};
/**
* ★No.269 / 270: 宣言の関係の警告 (辞書メンテナンス / EDM属性CSV一括登録 / 物理属性CSV一括登録で共通)。
* items = [{ label, raw (宣言。 カンマ区切り可), selfCd, selfProjects? (配列。 省略 = DB の PROJECT_ID) }]
* - 同じトークンを他のデータドメインも宣言: プロジェクトが重なれば警告 (mainte.edmAttrDup.warn)、 重ならなければ参考 (mainte.edmAttrDup.info)
* - 包含 (「E.A」と「A」): 同じデータドメイン = 警告 (self)、 他のデータドメイン = 重なれば警告 / 重ならなければ参考。 同じ確定の中の行どうしも見る
*/
TFC.warnEdmDeclRelations = function (lang, items, opts) {
var EN = (lang === 'en');
opts = opts || {};
try {
var defs = TFC.selectPS('SELECT A.DOMAIN_CD, A.EDM_ATTR, D.MAIN_NM, D.PROJECT_ID FROM TLN_M_FUNC_DOMAIN_EDM_DEF A ' +
'LEFT OUTER JOIN TLN_M_FUNC_DOMAIN D ON D.DOMAIN_CD = A.DOMAIN_CD', []);
var byKey = {}, byAttr = {}, projOf = {}, nameOf = {}, i, j;
var attrPart = function (key) { var p = key.lastIndexOf('.'); return p > 0 ? key.substring(p + 1) : key; };
for (i = 0; i < defs.length; i++) {
var dcd = TFC.s(defs[i]['DOMAIN_CD']), dk = _edmDefKey(defs[i]['EDM_ATTR']);
if (!dcd || !dk) continue;
projOf[dcd] = TFC.s(defs[i]['PROJECT_ID']); nameOf[dcd] = TFC.s(defs[i]['MAIN_NM']) || dcd;
if (!byKey[dk]) byKey[dk] = {};
byKey[dk][dcd] = 1;
var ap = attrPart(dk);
if (!byAttr[ap]) byAttr[ap] = [];
byAttr[ap].push({ cd: dcd, key: dk, tok: TFC.s(defs[i]['EDM_ATTR']) });
}
var selfProj = function (it) { return it.selfProjects || TFC.splitProjectIds(projOf[it.selfCd] || ''); };
var overlap = function (it, cd) { return TFC.projectsOverlap(selfProj(it), TFC.splitProjectIds(projOf[cd] || '')); };
var lbl = function (cd, tok) { return (tok ? ('「' + tok + '」 ') : '') + nameOf[cd] + ' (' + cd + ')'; };
// 同じ確定の中の行 (データドメインごとのキー) — DB にまだ無い宣言どうしの包含
var mineByCd = {};
for (i = 0; i < items.length; i++) {
var tks0 = TFC.parseEdmAttrDecl(items[i].raw);
for (j = 0; j < tks0.length; j++) { var k0 = _edmDefKey(tks0[j]); if (!mineByCd[items[i].selfCd]) mineByCd[items[i].selfCd] = {}; if (!mineByCd[items[i].selfCd][k0]) mineByCd[items[i].selfCd][k0] = tks0[j]; }
}
for (i = 0; i < items.length; i++) {
var it = items[i], toks = TFC.parseEdmAttrDecl(it.raw);
for (j = 0; j < toks.length; j++) {
var key = _edmDefKey(toks[j]), q = key.indexOf('.') > 0, ap2 = attrPart(key), cd2;
var warn = [], info = [];
var hit = byKey[key] || {};
for (cd2 in hit) if (hit.hasOwnProperty(cd2) && cd2 !== it.selfCd) (overlap(it, cd2) ? warn : info).push(lbl(cd2, ''));
warn.sort(); info.sort();
if (warn.length) TALON.addWornMsg(TFC.tf('mainte.edmAttrDup.warn', lang, [it.label, toks[j], warn.join(EN ? ', ' : '、 ')]));
if (info.length) TALON.addMsg(TFC.tf('mainte.edmAttrDup.info', lang, [it.label, toks[j], info.join(EN ? ', ' : '、 ')]));
// 包含: 精度の違う同じ属性 (DB の宣言 + 同じ確定の中の行)
var selfIncl = [], inclWarn = [], inclInfo = [], rel = byAttr[ap2] || [], seenRel = {}, r;
for (r = 0; r < rel.length; r++) {
if (rel[r].key === key || (rel[r].key.indexOf('.') > 0) === q) continue;
var rk = rel[r].cd + '|' + rel[r].key;
if (seenRel[rk]) continue;
seenRel[rk] = 1;
if (rel[r].cd === it.selfCd) selfIncl.push(rel[r].tok);
else (overlap(it, rel[r].cd) ? inclWarn : inclInfo).push(lbl(rel[r].cd, rel[r].tok));
}
var mine = mineByCd[it.selfCd] || {}, mk;
for (mk in mine) if (mine.hasOwnProperty(mk) && mk !== key && (mk.indexOf('.') > 0) !== q && attrPart(mk) === ap2 && !seenRel[it.selfCd + '|' + mk]) selfIncl.push(mine[mk]);
selfIncl.sort(); inclWarn.sort(); inclInfo.sort();
if (selfIncl.length) TALON.addWornMsg(TFC.tf('mainte.edmAttrIncl.self.warn', lang, [it.label, toks[j], selfIncl.join(EN ? ', ' : '、 ')]));
if (inclWarn.length) TALON.addWornMsg(TFC.tf('mainte.edmAttrIncl.warn', lang, [it.label, toks[j], inclWarn.join(EN ? ', ' : '、 ')]));
if (inclInfo.length) TALON.addMsg(TFC.tf('mainte.edmAttrIncl.info', lang, [it.label, toks[j], inclInfo.join(EN ? ', ' : '、 ')]));
}
}
} catch (eDup) { try { TALON.getLogger().writeInfo('[TFC-DOMAIN] EDM 属性の宣言の関係チェックをスキップ: ' + eDup); } catch (ig2) {} }
};
/**
* ★No.265: 物理属性から外れて使われなくなった宣言を消す。 前の版 (改訂履歴の最新版) で物理属性が実装していたトークンのうち、 今はどの物理属性も実装せず、
* コメントも無い宣言 (= 手で書いた形跡が無い) を補完表から消す。 コメント付きの宣言と、 元々物理属性に紐付いていなかった宣言 (「EDM属性」タブで書いたもの) は残す。
* 履歴の無いデータドメイン (初回) は前の版が分からないので何もしない。 opts = { domainCd, lang, srcFuncId, now, by }。 戻り { del, tokens }
*/
TFC.pruneOrphanEdmDefs = function (opts) {
var res = { del: 0, tokens: [] };
opts = opts || {};
if (!opts.domainCd || !TFC.edmDefAvailable()) return res;
var cd = opts.domainCd, prev;
try {
prev = TFC.selectPS('SELECT EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR_HIS WHERE DOMAIN_CD = ? AND CHANGE_KBN <> ? AND EDM_ATTR IS NOT NULL AND REV_NO = ' +
'(SELECT MAX(REV_NO) FROM TLN_M_FUNC_DOMAIN_ATTR_HIS WHERE DOMAIN_CD = ?)', [cd, 'D', cd]);
} catch (eH) { return res; } /* 履歴表が無い環境 */
if (!prev.length) return res;
var curKeys = {}, i, k;
var cur = TFC.selectPS('SELECT EDM_ATTR FROM TLN_M_FUNC_DOMAIN_ATTR WHERE DOMAIN_CD = ? AND EDM_ATTR IS NOT NULL', [cd]);
for (i = 0; i < cur.length; i++) { var ct = TFC.parseEdmAttrDecl(TFC.s(cur[i]['EDM_ATTR'])); for (k = 0; k < ct.length; k++) curKeys[_edmDefKey(ct[k])] = 1; }
var gone = {}, any = false;
for (i = 0; i < prev.length; i++) { var pt = TFC.parseEdmAttrDecl(TFC.s(prev[i]['EDM_ATTR'])); for (k = 0; k < pt.length; k++) { var pk = _edmDefKey(pt[k]); if (pk && !curKeys[pk]) { gone[pk] = 1; any = true; } } }
if (!any) return res;
var defs = TFC.selectPS('SELECT EDM_ATTR, DEF_COMMENT FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ?', [cd]);
for (i = 0; i < defs.length; i++) {
var dk = _edmDefKey(defs[i]['EDM_ATTR']);
if (!gone[dk] || TFC.s(defs[i]['DEF_COMMENT']).replace(/[\s ]+/g, '')) continue;
res.del += TFC.updatePS('DELETE FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [cd, TFC.s(defs[i]['EDM_ATTR'])]);
res.tokens.push(TFC.s(defs[i]['EDM_ATTR']));
}
if (res.del && opts.lang) TALON.addMsg(TFC.tf('mainte.orphanDefPruned', opts.lang, [String(res.del), res.tokens.join(opts.lang === 'en' ? ', ' : '、 ')]));
return res;
};
/** 付け替え: 補完行を fromCd から toCd へ移す (移す先に同じ宣言の行があれば空の項目だけ埋めて、 元の行を消す) */
TFC.moveEdmDefRow = function (fromCd, toCd, tok, meta) {
if (!TFC.edmDefAvailable()) return false;
var src = _edmDefFind(fromCd, tok);
if (!src) return false;
var m = _edmDefMeta(meta);
var dst = _edmDefFind(toCd, tok);
if (dst) {
var nlm = function (v) { return TFC.s(v).replace(/\r\n?/g, '\n'); };
var nc = nlm(dst['DEF_COMMENT']) || nlm(src['DEF_COMMENT']);
if (nc !== nlm(dst['DEF_COMMENT'])) {
TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET DEF_COMMENT = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, ' +
'MODIFY_COUNT = MODIFY_COUNT + 1 WHERE DOMAIN_CD = ? AND EDM_ATTR = ?',
[nc || null, m.now, m.by, m.prg, toCd, TFC.s(dst['EDM_ATTR'])]);
}
TFC.updatePS('DELETE FROM ' + DOMAIN_EDM_DEF + ' WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [fromCd, TFC.s(src['EDM_ATTR'])]);
} else {
TFC.updatePS('UPDATE ' + DOMAIN_EDM_DEF + ' SET DOMAIN_CD = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ?, MODIFY_COUNT = MODIFY_COUNT + 1 ' +
'WHERE DOMAIN_CD = ? AND EDM_ATTR = ?', [toCd, m.now, m.by, m.prg, fromCd, TFC.s(src['EDM_ATTR'])]);
}
return true;
};
/** 設計書出力用: DOMAIN_CD → { トークン(UPPER) → { edmAttr, comment } } (表が無ければ {}) */
TFC.loadEdmDefRows = function () {
var out = {};
if (!TFC.edmDefAvailable()) return out;
var rows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR, DEF_COMMENT FROM ' + DOMAIN_EDM_DEF + ' ORDER BY DOMAIN_CD, EDM_ATTR', []);
for (var i = 0; i < rows.length; i++) {
var cd = TFC.s(rows[i]['DOMAIN_CD']), tok = _edmDefNormTok(rows[i]['EDM_ATTR']);
if (!cd || !tok) continue;
if (!out[cd]) out[cd] = {};
out[cd][tok.toUpperCase()] = { edmAttr: tok, comment: TFC.s(rows[i]['DEF_COMMENT']) };
}
return out;
};
// [[EDM-DEF-MODULE-END]]
// ★Ver1.0.13 (No.183): 履歴の無い行が「この確定より前から存在した」か (版上げ直後、 設計書出力より先に画面で確定したとき)。
// 新規行は CREATED_DATE = UPDATED_DATE (TALON が同時に入れる)。 更新された既存行は UPDATED_DATE が後 → 'S' (初期取込) として版 1 にする
// (変更前の値は残っていないので、 この確定の変更内容は版に分けられない)。
function _hisPreExisting(row, ref, since) {
try {
var cm = _hisMillis(row['CREATED_DATE']), um = _hisMillis(row['UPDATED_DATE']);
if (cm == null || um == null) return false;
if ((um - cm) > 1000) return true; // 1 秒超の差 = 別の確定で更新された既存行
// ★Ver1.0.22 (No.183 確認NG): 登録後に一度も更新していない既存行は CREATED = UPDATED のまま → 基準時刻より 5 分以上前に書かれた行は既存。
// ★★基準 (ref) は「現在行の中で最も新しい UPDATED_DATE」(= この確定で TALON が書いた行の時刻、 _hisRefMillis)。 同じ書き手の値どうしを
// 相対で比べるので、 DB と JVM の時差 (テスター環境で 9 時間 — 2026-09-30 確認NG) や日時の文字列解釈に左右されない。 確定後 JS の開始時刻
// (since / now = JVM の時計) は基準が取れないときの後備え。
var sm = _hisMillis(ref);
if (sm != null && um < sm - 300000) return true;
// 後備え: 確定後 JS の開始時刻 (JVM の時計) より 5 分以上前 = この確定で何も書かなかったとき (最新行が古い) に効く。 行の時計が JVM より進む
// 時差 (テスター環境) では「未来」に見えるだけで誤判定しない。 逆向きの時差では新規行が S に寄るが、 I が S になる側の誤りに留める。
var ss = _hisMillis(since);
return ss != null && um < ss - 300000;
} catch (e) { return false; }
}
// 現在行の UPDATED_DATE の最大 (この確定で書いた行の時刻)。 無ければ fallback (since / now)
function _hisRefMillis(rows, fallback) {
var mx = null;
for (var i = 0; i < rows.length; i++) {
var m = _hisMillis(rows[i]['UPDATED_DATE'] || rows[i]['CREATED_DATE']);
if (m != null && (mx == null || m > mx)) mx = m;
}
return mx != null ? mx : fallback;
}
function _hisMillis(v) {
try {
if (v == null) return null;
if (typeof v === 'number') return isNaN(v) ? null : v; // 既に millis (_hisRefMillis の戻り)
if (typeof v.getTime === 'function') { var t = Number(v.getTime()); return isNaN(t) ? null : t; }
// 文字列の日時 ('2026-09-30 10:00:00.0' 等) はローカル時刻として読む (Date.parse は Nashorn で UTC 扱いになり 9 時間ずれる)
var mt = /^\s*(\d{4})[-\/](\d{1,2})[-\/](\d{1,2})(?:[ T](\d{1,2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?)?\s*$/.exec(String(v));
if (mt) {
var lt = new Date(Number(mt[1]), Number(mt[2]) - 1, Number(mt[3]), Number(mt[4] || 0), Number(mt[5] || 0), Number(mt[6] || 0),
Number((mt[7] || '0') + '00'.substring(0, 3 - (mt[7] || '0').length))).getTime();
return isNaN(lt) ? null : lt;
}
var p = Date.parse(String(v));
return isNaN(p) ? null : p;
} catch (e) { return null; }
}
function _hisYm(ts) {
var ms = null;
try { if (ts != null && typeof ts.getTime === 'function') ms = Number(ts.getTime()); } catch (e) {}
var d = (ms != null && !isNaN(ms)) ? new Date(ms) : new Date();
return d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2);
}
function _hisNow() {
return new (Java.type('java.sql.Timestamp'))(Java.type('java.lang.System').currentTimeMillis());
}
function _hisActor(opts) {
var u = TFC.s(opts && opts.userId);
if (!u) { try { u = TFC.s(TALON.getUserInfoMap().USER_ID); } catch (e) {} }
return u || 'SYSTEM';
}
function _hisKeyOf(row, keys) {
var parts = [];
for (var i = 0; i < keys.length; i++) parts.push(TFC.s(row[keys[i]]).replace(/\.0+$/, ''));
return parts.join('');
}
function _hisIsOracle(conn) {
if (_hisIsOracleCache == null) {
try { _hisIsOracleCache = String(conn.getMetaData().getDatabaseProductName() || '').toLowerCase().indexOf('oracle') >= 0; }
catch (e) { _hisIsOracleCache = false; }
}
return _hisIsOracleCache;
}
function _hisTablesExist() {
try { TFC.tableColumns(DOMAIN_HIS); TFC.tableColumns(DOMAIN_ATTR_HIS); return true; }
catch (e) { return false; }
}
TFC.domainHistoryAvailable = _hisTablesExist;
// Ver1.0.14: 補完表とその履歴表の両方がある環境だけ定義域を版に写す
function _hisDefAvailable() {
try { TFC.tableColumns(DOMAIN_EDM_DEF); TFC.tableColumns(DOMAIN_EDM_DEF_HIS); return true; }
catch (e) { return false; }
}
function _hisDefKey(row) { return TFC.s(row['EDM_ATTR']).replace(/./g, '.').replace(/[\s ]+/g, ' ').replace(/^ | $/g, '').toUpperCase(); }
// 辞書の最新版に写っている定義域 (D を除く) — DOMAIN_CD → { トークン(UPPER) → 行 }
function _hisLatestDefSnapshot() {
var rows = TFC.selectPS('SELECT a.DOMAIN_CD, a.EDM_ATTR, a.CHANGE_KBN, a.' + _HIS_DEF_COLS.join(', a.') +
' FROM ' + DOMAIN_EDM_DEF_HIS + ' a INNER JOIN (SELECT DOMAIN_CD, MAX(REV_NO) AS MAXREV FROM ' + DOMAIN_HIS +
' GROUP BY DOMAIN_CD) m ON m.DOMAIN_CD = a.DOMAIN_CD AND m.MAXREV = a.REV_NO', []);
var out = {};
for (var i = 0; i < rows.length; i++) {
if (TFC.s(rows[i]['CHANGE_KBN']) === 'D') continue;
var cd = TFC.s(rows[i]['DOMAIN_CD']);
(out[cd] = out[cd] || {})[_hisDefKey(rows[i])] = rows[i];
}
return out;
}
// 1 版を INSERT。 vals は names と同じ並び。 長文列 (longIdx=true) は Oracle で 4000 文字超なら文字ストリームで渡す
function _hisInsert(table, names, vals, longIdx) {
var sql = 'INSERT INTO ' + table + ' (' + names.join(', ') + ') VALUES (' +
names.map(function () { return '?'; }).join(', ') + ')';
var dbConfig = TALON.getDbConfig();
var conn = _getConn(dbConfig);
var stmt = null;
try {
stmt = conn.prepareStatement(sql);
var ora = _hisIsOracle(conn);
for (var i = 0; i < vals.length; i++) {
var v = vals[i];
if (longIdx[i] && typeof v === 'string' && ora && v.length > _HIS_ORACLE_INLINE_MAX) {
stmt.setCharacterStream(i + 1, new (Java.type('java.io.StringReader'))(v), v.length);
} else {
stmt.setObject(i + 1, v);
}
}
return stmt.executeUpdate();
} finally {
if (stmt != null) { try { stmt.close(); } catch (e) {} }
}
}
// ★主キー (コード, 版) の重複 = 同時更新で同じ版番号を採ったとき: セーブポイントまで戻し、 最新の版番号を読み直して 1 回だけやり直す
// (呼び出し元の画面は排他制御 (MODIFY_COUNT) が効くので通常は起きない。 設計書出力の追いつきとの同時実行の保険。 2026-09-22 ユーザー指摘)
function _hisIsDup(e) {
var m = String((e && (e.message || e.getMessage && e.getMessage())) || e || '');
return /ORA-00001|duplicate|23505|2627|1062|unique constraint|一意制約/i.test(m);
}
function _hisMaxRev(table, keyCol, keyVal) {
var rows = TFC.selectPS('SELECT MAX(REV_NO) AS MAXREV FROM ' + table + ' WHERE ' + keyCol + ' = ?', [keyVal]);
var v = (rows && rows.length) ? rows[0]['MAXREV'] : null;
return v == null ? 0 : Number(TFC.s(v)) || 0;
}
function _hisWithRetry(table, keyCol, keyVal, rev, writeFn) {
var conn = null, sp = null;
try { conn = _getConn(TALON.getDbConfig()); sp = conn.setSavepoint(); } catch (eS) { sp = null; }
try { writeFn(rev); return rev; }
catch (e) {
if (!_hisIsDup(e)) throw e;
if (sp) { try { conn.rollback(sp); } catch (eR) {} }
var r2 = _hisMaxRev(table, keyCol, keyVal) + 1;
if (r2 <= rev) r2 = rev + 1;
try { TALON.getLogger().writeWarn('[TFC] 改訂履歴: ' + table + ' ' + keyVal + ' 版 ' + rev + ' が重複 (同時更新) → 版 ' + r2 + ' で再試行'); } catch (eL) {}
writeFn(r2); return r2;
}
}
// ★版の付け方 (ユーザー決定 2026-09-21): 辞書 1 件の版はスナップショット。 辞書の業務列か物理属性 (追加 / 更新 / 削除) の
// どれかが変わったら辞書の版を 1 つ進め、 その版に物理属性の全行を写す (変わった行は I / U / D、 変わっていない行は N = 変更なし)。
// 「版 N の辞書 = 定義 + 物理属性の一覧」が 1 つの版番号で読める。 物理属性が変わっただけの版は CHANGED_COLS に 'ATTR' を入れる。
// (第 1 段の初版では属性ごとに独立した版番号を振っていたが、 一覧で「版 2 = 属性 4 本」と読めるこの形に変えた)
function _hisLatestDomains() {
var rows = TFC.selectPS('SELECT h.DOMAIN_CD, h.REV_NO, h.CHANGE_KBN, h.' + _HIS_DOM_COLS.join(', h.') +
' FROM ' + DOMAIN_HIS + ' h INNER JOIN (SELECT DOMAIN_CD, MAX(REV_NO) AS MAXREV FROM ' + DOMAIN_HIS +
' GROUP BY DOMAIN_CD) m ON m.DOMAIN_CD = h.DOMAIN_CD AND m.MAXREV = h.REV_NO', []);
var out = {};
for (var i = 0; i < rows.length; i++) out[TFC.s(rows[i]['DOMAIN_CD'])] = rows[i];
return out;
}
// 辞書の最新版に写っている物理属性 (D を除く) — DOMAIN_CD → { SEQ_NO キー → 行 }
function _hisLatestAttrSnapshot() {
var rows = TFC.selectPS('SELECT a.DOMAIN_CD, a.SEQ_NO, a.CHANGE_KBN, a.' + _HIS_ATTR_COLS.join(', a.') +
' FROM ' + DOMAIN_ATTR_HIS + ' a INNER JOIN (SELECT DOMAIN_CD, MAX(REV_NO) AS MAXREV FROM ' + DOMAIN_HIS +
' GROUP BY DOMAIN_CD) m ON m.DOMAIN_CD = a.DOMAIN_CD AND m.MAXREV = a.REV_NO', []);
var out = {};
for (var i = 0; i < rows.length; i++) {
if (TFC.s(rows[i]['CHANGE_KBN']) === 'D') continue;
var cd = TFC.s(rows[i]['DOMAIN_CD']);
(out[cd] = out[cd] || {})[_hisKeyOf(rows[i], ['SEQ_NO'])] = rows[i];
}
return out;
}
/**
* 改訂履歴の追記 (辞書 + 物理属性、 スナップショット方式)。
* @param opts { srcFuncId: 検出した機能 ID, userId: 削除の変更者 (省略時はログインユーザ), initial: true なら新規行を 'S' 初期取込 }
* @return { dom: {ins, upd, del, init}, attr: {ins, upd, del, init, keep}, skipped }
*/
TFC.recordDomainHistory = function (opts) {
opts = opts || {};
var res = { dom: { ins: 0, upd: 0, del: 0, init: 0 }, attr: { ins: 0, upd: 0, del: 0, init: 0, keep: 0 },
def: { ins: 0, upd: 0, del: 0, init: 0, keep: 0 }, skipped: false }; // Ver1.0.14: def = 辞書側の定義域 (補完行)
if (!_hisTablesExist()) { res.skipped = true; return res; }
var ctx = { src: _edmCatCut(TFC.s(opts.srcFuncId) || 'TFC', 64), actor: _hisActor(opts),
initial: !!opts.initial, now: _hisNow(), since: opts.since || null }; // since: 確定後 JS の開始 (No.183)
var curDoms = TFC.selectPS('SELECT DOMAIN_CD, ' + _HIS_DOM_COLS.join(', ') +
', CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE, MODIFY_COUNT FROM TLN_M_FUNC_DOMAIN', []);
ctx.ref = _hisRefMillis(curDoms, ctx.since || ctx.now); // ★No.183 確認NG (2026-09-30): 既存判定の基準 = 現在行の最新 UPDATED_DATE (時差に依存しない)
var curAttrRows = TFC.selectPS('SELECT DOMAIN_CD, SEQ_NO, ' + _HIS_ATTR_COLS.join(', ') +
', CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE, MODIFY_COUNT FROM TLN_M_FUNC_DOMAIN_ATTR', []);
var curAttrs = {};
for (var ai = 0; ai < curAttrRows.length; ai++) {
var acd = TFC.s(curAttrRows[ai]['DOMAIN_CD']);
(curAttrs[acd] = curAttrs[acd] || {})[_hisKeyOf(curAttrRows[ai], ['SEQ_NO'])] = curAttrRows[ai];
}
var lastDom = _hisLatestDomains(), lastAttr = _hisLatestAttrSnapshot();
// ★Ver1.0.14: 辞書側の定義域 (補完行) も版に写す (表がある環境だけ)。 キー = 宣言トークン (UPPER)
var defAvail = _hisDefAvailable();
var curDefs = {}, lastDef = {};
if (defAvail) {
var curDefRows = TFC.selectPS('SELECT DOMAIN_CD, EDM_ATTR, ' + _HIS_DEF_COLS.join(', ') +
', CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE, MODIFY_COUNT FROM ' + DOMAIN_EDM_DEF, []);
for (var dfi = 0; dfi < curDefRows.length; dfi++) {
var dcd = TFC.s(curDefRows[dfi]['DOMAIN_CD']);
(curDefs[dcd] = curDefs[dcd] || {})[_hisDefKey(curDefRows[dfi])] = curDefRows[dfi];
}
lastDef = _hisLatestDefSnapshot();
}
var defNames = ['DOMAIN_CD', 'EDM_ATTR'].concat(_HIS_META_COLS).concat(_HIS_DEF_COLS);
var defLong = [];
for (var dli = 0; dli < defNames.length; dli++) defLong.push(false);
function noCh() { return { added: [], updated: {}, removed: [], any: false }; }
var domNames = ['DOMAIN_CD'].concat(_HIS_META_COLS).concat(_HIS_DOM_COLS);
var domLong = [];
for (var di = 0; di < domNames.length; di++) domLong.push(!!_HIS_DOM_LONG[domNames[di]]);
var attrNames = ['DOMAIN_CD', 'SEQ_NO'].concat(_HIS_META_COLS).concat(_HIS_ATTR_COLS);
var attrLong = [];
for (var li = 0; li < attrNames.length; li++) attrLong.push(false);
function metaVals(kbn, rev, by, at, cols, mod) {
var who = _edmCatCut(TFC.s(ctx.actor), 50), prg = _edmCatCut(TFC.s(ctx.src), 50);
return [_JInt.valueOf(rev), kbn, _edmCatCut(TFC.s(by), 50), at, _hisYm(at), ctx.src,
_edmCatCut(cols.join(','), _HIS_COLS_MAX), _JInt.valueOf(0),
ctx.now, who, prg, ctx.now, who, prg];
}
function colVals(cols, longCols, row) {
var out = [];
for (var ci = 0; ci < cols.length; ci++) {
var v = longCols[cols[ci]] ? _hisNormVal(row[cols[ci]]) : TFC.s(row[cols[ci]]);
out.push(v === '' ? null : v);
}
return out;
}
function rowBy(row) { return TFC.s(row['UPDATED_BY']) || TFC.s(row['CREATED_BY']) || ctx.actor; }
function rowAt(row) { return row['UPDATED_DATE'] || row['CREATED_DATE'] || ctx.now; }
function attrChanges(curMap, prevMap, cols) {
cols = cols || _HIS_ATTR_COLS;
var ch = { added: [], updated: {}, removed: [], any: false }, k;
for (k in curMap) {
if (!curMap.hasOwnProperty(k)) continue;
if (!prevMap[k]) { ch.added.push(k); ch.any = true; continue; }
var d = _hisDiffCols(cols, curMap[k], prevMap[k]);
if (d.length) { ch.updated[k] = d; ch.any = true; }
}
for (k in prevMap) {
if (prevMap.hasOwnProperty(k) && !curMap[k]) { ch.removed.push(k); ch.any = true; }
}
return ch;
}
// その版に物理属性の全行を写す (newKbn = 前の版に無い行の種別: 'I' / 'S')
function writeAttrs(cd, rev, curMap, prevMap, ch, newKbn) {
var k;
for (k in curMap) {
if (!curMap.hasOwnProperty(k)) continue;
var row = curMap[k], kbn, cols = [];
if (!prevMap[k]) kbn = newKbn;
else if (ch.updated[k]) { kbn = 'U'; cols = ch.updated[k]; }
else kbn = 'N';
_hisInsert(DOMAIN_ATTR_HIS, attrNames,
[cd, row['SEQ_NO']].concat(metaVals(kbn, rev, rowBy(row), rowAt(row), cols, row['MODIFY_COUNT']))
.concat(colVals(_HIS_ATTR_COLS, {}, row)), attrLong);
res.attr[kbn === 'S' ? 'init' : (kbn === 'I' ? 'ins' : (kbn === 'U' ? 'upd' : 'keep'))]++;
}
for (k in prevMap) {
if (!prevMap.hasOwnProperty(k) || curMap[k]) continue;
_hisInsert(DOMAIN_ATTR_HIS, attrNames,
[cd, prevMap[k]['SEQ_NO']].concat(metaVals('D', rev, ctx.actor, ctx.now, [], null))
.concat(colVals(_HIS_ATTR_COLS, {}, prevMap[k])), attrLong);
res.attr.del++;
}
}
// Ver1.0.14: その版に辞書側の定義域 (補完行) の全行を写す (writeAttrs と同じ規則)
function writeDefs(cd, rev, curMap, prevMap, ch, newKbn) {
if (!defAvail) return;
var k;
for (k in curMap) {
if (!curMap.hasOwnProperty(k)) continue;
var row = curMap[k], kbn, cols = [];
if (!prevMap[k]) kbn = newKbn;
else if (ch.updated[k]) { kbn = 'U'; cols = ch.updated[k]; }
else kbn = 'N';
_hisInsert(DOMAIN_EDM_DEF_HIS, defNames,
[cd, TFC.s(row['EDM_ATTR'])].concat(metaVals(kbn, rev, rowBy(row), rowAt(row), cols, row['MODIFY_COUNT']))
.concat(colVals(_HIS_DEF_COLS, {}, row)), defLong);
res.def[kbn === 'S' ? 'init' : (kbn === 'I' ? 'ins' : (kbn === 'U' ? 'upd' : 'keep'))]++;
}
for (k in prevMap) {
if (!prevMap.hasOwnProperty(k) || curMap[k]) continue;
_hisInsert(DOMAIN_EDM_DEF_HIS, defNames,
[cd, TFC.s(prevMap[k]['EDM_ATTR'])].concat(metaVals('D', rev, ctx.actor, ctx.now, [], null))
.concat(colVals(_HIS_DEF_COLS, {}, prevMap[k])), defLong);
res.def.del++;
}
}
var seen = {};
for (var ri = 0; ri < curDoms.length; ri++) {
var row = curDoms[ri], cd = TFC.s(row['DOMAIN_CD']);
if (!cd) continue;
seen[cd] = 1;
var prev = lastDom[cd];
var curMap = curAttrs[cd] || {};
var prevMap = (prev && TFC.s(prev['CHANGE_KBN']) !== 'D') ? (lastAttr[cd] || {}) : {};
var curDefMap = curDefs[cd] || {};
var prevDefMap = (prev && TFC.s(prev['CHANGE_KBN']) !== 'D') ? (lastDef[cd] || {}) : {};
var kbn, rev, cols, by, at;
if (!prev || TFC.s(prev['CHANGE_KBN']) === 'D') {
kbn = (ctx.initial || _hisPreExisting(row, ctx.ref, ctx.since || ctx.now)) ? 'S' : 'I'; // ★Ver1.0.13 (No.183): 履歴の無い既存行は初期取込 (Ver1.0.22: 未更新の既存行も)
rev = prev ? Number(TFC.s(prev['REV_NO'])) + 1 : 1;
cols = []; by = rowBy(row); at = rowAt(row);
_hisWithRetry(DOMAIN_HIS, 'DOMAIN_CD', cd, rev, function (r) {
_hisInsert(DOMAIN_HIS, domNames, [cd].concat(metaVals(kbn, r, by, at, cols, row['MODIFY_COUNT'])).concat(colVals(_HIS_DOM_COLS, _HIS_DOM_LONG, row)), domLong);
writeAttrs(cd, r, curMap, {}, noCh(), kbn);
writeDefs(cd, r, curDefMap, {}, noCh(), kbn);
});
res.dom[kbn === 'S' ? 'init' : 'ins']++;
continue;
}
var domDiff = _hisDiffCols(_HIS_DOM_COLS, row, prev);
var ch = attrChanges(curMap, prevMap);
var chD = defAvail ? attrChanges(curDefMap, prevDefMap, _HIS_DEF_COLS) : noCh(); // Ver1.0.14
if (domDiff.length === 0 && !ch.any && !chD.any) continue;
rev = Number(TFC.s(prev['REV_NO'])) + 1;
cols = domDiff.concat(ch.any ? ['ATTR'] : []).concat(chD.any ? ['EDM_DEF'] : []);
if (domDiff.length) { by = rowBy(row); at = rowAt(row); }
else {
// 物理属性だけの変更: 変わった属性のうち一番新しい更新者 / 日時 (削除だけなら確定した利用者 / 検出時刻)
by = ctx.actor; at = ctx.now; var best = null;
var chKeys = ch.added.concat(Object.keys(ch.updated)), chDKeys = chD.added.concat(Object.keys(chD.updated));
for (var ki = 0; ki < chKeys.length + chDKeys.length; ki++) {
var r2 = ki < chKeys.length ? curMap[chKeys[ki]] : curDefMap[chDKeys[ki - chKeys.length]], t2 = rowAt(r2), ms = 0;
try { ms = (t2 && typeof t2.getTime === 'function') ? Number(t2.getTime()) : 0; } catch (eT) { ms = 0; }
if (best == null || ms > best) { best = ms; by = rowBy(r2); at = t2; }
}
}
_hisWithRetry(DOMAIN_HIS, 'DOMAIN_CD', cd, rev, function (r) {
_hisInsert(DOMAIN_HIS, domNames, [cd].concat(metaVals('U', r, by, at, cols, row['MODIFY_COUNT'])).concat(colVals(_HIS_DOM_COLS, _HIS_DOM_LONG, row)), domLong);
writeAttrs(cd, r, curMap, prevMap, ch, 'I');
writeDefs(cd, r, curDefMap, prevDefMap, chD, 'I');
});
res.dom.upd++;
}
// 削除: 最新版があるのに現在無い (最新版が既に 'D' なら二重に書かない)。 物理属性も同じ版で 'D'
for (var dk in lastDom) {
if (!lastDom.hasOwnProperty(dk) || seen[dk]) continue;
var lp = lastDom[dk];
if (TFC.s(lp['CHANGE_KBN']) === 'D') continue;
var drev = Number(TFC.s(lp['REV_NO'])) + 1;
_hisWithRetry(DOMAIN_HIS, 'DOMAIN_CD', dk, drev, function (r) {
_hisInsert(DOMAIN_HIS, domNames, [dk].concat(metaVals('D', r, ctx.actor, ctx.now, [], null)).concat(colVals(_HIS_DOM_COLS, _HIS_DOM_LONG, lp)), domLong);
writeAttrs(dk, r, {}, lastAttr[dk] || {}, { added: [], updated: {}, removed: [], any: true }, 'I');
writeDefs(dk, r, {}, lastDef[dk] || {}, { added: [], updated: {}, removed: [], any: true }, 'I');
});
res.dom.del++;
}
return res;
};
/**
* 設計書出力用: DOMAIN_CD → 直近 limit 版 (新しい順) の配列 [{rev, kbn, by, at, ym, cols, src}]。
* 履歴テーブルが無ければ {} を返す。 ATTR の履歴は含めない (設計書ではカードに載せない)。
*/
TFC.loadDomainHistory = function (limit) {
var out = {};
if (!_hisTablesExist()) return out;
var lim = limit || 5;
var rows = TFC.selectPS('SELECT DOMAIN_CD, REV_NO, CHANGE_KBN, CHANGED_BY, CHANGED_DATE, CHANGED_YM, CHANGED_COLS, SRC_FUNC_ID FROM ' +
DOMAIN_HIS + ' ORDER BY DOMAIN_CD, REV_NO DESC', []);
for (var i = 0; i < rows.length; i++) {
var r = rows[i], cd = TFC.s(r['DOMAIN_CD']);
if (!out[cd]) out[cd] = { total: 0, revs: [] };
out[cd].total++;
if (out[cd].revs.length < lim) {
out[cd].revs.push({ rev: Number(TFC.s(r['REV_NO'])), kbn: TFC.s(r['CHANGE_KBN']), by: TFC.s(r['CHANGED_BY']),
at: r['CHANGED_DATE'], ym: TFC.s(r['CHANGED_YM']), cols: TFC.s(r['CHANGED_COLS']),
src: TFC.s(r['SRC_FUNC_ID']) });
}
}
return out;
};
// [[DOMAIN-HISTORY-MODULE-END]]
// ============================================================
// [[EDM-HISTORY-MODULE-BEGIN]]
// EDM (TLN_M_FUNC_EDM) の改訂履歴 (Ver1.0.6、 ユーザー追加要望): 版ごとに .a5er とプレビュー SVG の複製を残し、
// 履歴一覧でサムネイルを並べてモデルの変遷を見る。
// - 辞書の履歴と同じ差分検出 (TFC.recordDomainHistory と同じ流儀)。 業務列 (PROJECT_ID / EDM_NM / SORT_NO / NOTE /
// SRC_FILE の DB 値) に加えて .a5er の中身 (SHA-256) を比べる → ファイルだけ差し替えた確定も版になる。
// - 版のファイルは {THUMBNAIL}/TLN_M_FUNC_EDM/SRC_FILE/history/TLN_M_FUNC_EDM_SRC_FILE_{EDM_CD}_r{REV}.a5er / .svg。
// DB には TALON の FILE 項目と同じ形 (物理パス//元ファイル名) で持ち、 一覧の読み取り専用 FILE 項目が
// .svg をサムネイル表示、 .a5er をダウンロードリンクにする (EDM 画面の SVG_VIEW と同じ仕組み)。
// - 削除は 'D' の版 (ファイルは直前の版のものをそのまま指す)。 呼び出し点: EDM 確定後フック (プレビュー生成の後) /
// SETUP (initial=true → 'S') / 設計書出力の開始。 履歴表が無い環境では何もしない。
// ============================================================
var EDM_HIS = 'TLN_M_FUNC_EDM_HIS';
var _EDM_HIS_COLS = ['PROJECT_ID', 'EDM_NM', 'SORT_NO', 'NOTE', 'SRC_FILE'];
var _EDM_HIS_DIR = 'TLN_M_FUNC_EDM/SRC_FILE/history';
function _edmHisTablesExist() {
try { TFC.tableColumns(EDM_HIS); return true; } catch (e) { return false; }
}
TFC.edmHistoryAvailable = _edmHisTablesExist;
// ファイルの SHA-256 (16 進)。 無ければ ''
function _edmFileHash(path) {
if (!path) return '';
try {
var F = Java.type('java.nio.file.Files'), P = Java.type('java.nio.file.Paths');
var p = P.get(path);
if (!F.exists(p)) return '';
var d = Java.type('java.security.MessageDigest').getInstance('SHA-256').digest(F.readAllBytes(p));
var out = '';
for (var i = 0; i < d.length; i++) { var h = (d[i] & 0xff).toString(16); out += (h.length < 2 ? '0' : '') + h; }
return out;
} catch (e) { return ''; }
}
function _edmHisCopy(srcPath, dstPath) {
try {
var F = Java.type('java.nio.file.Files'), P = Java.type('java.nio.file.Paths');
var s = P.get(srcPath), d = P.get(dstPath);
if (!F.exists(s)) return false;
F.createDirectories(d.getParent());
F.copy(s, d, Java.type('java.nio.file.StandardCopyOption').REPLACE_EXISTING);
return true;
} catch (e) { return false; }
}
// DB 値 "物理//元名" の元ファイル名 (無ければ物理名の葉)
function _edmOrigName(srcVal) {
var v = TFC.s(srcVal), i = v.indexOf('//');
var nm = i >= 0 ? v.substring(i + 2) : v;
nm = nm.replace(/^.*[\\\/]/, '');
return nm;
}
// 版の「変更内容」(文字): 前の版と今の版の .a5er を軽量パーサ (TFC.parseA5er) で比べ、 エンティティの追加 / 削除、 属性の追加 / 削除、
// ドメイン欄の変更を列挙する。 最初の版はエンティティ数 / 属性数。 構造が同じ (配置だけ等) なら その旨。 lang は環境言語。
function _edmModelDiffText(prevText, curText, lang) {
var cur = curText ? TFC.parseA5er(curText) : null;
if (!cur) return '';
var prev = prevText ? TFC.parseA5er(prevText) : null;
function ekey(e) { return (e.cd || e.nm || '').toLowerCase(); }
function elabel(e) { return e.nm || e.cd || ''; }
function akey(x) { return (x.cd || x.nm || '').toLowerCase(); }
function alabel(x) { return x.nm || x.cd || ''; }
// Ver1.0.11: 型欄 = 定義域 (ツールのドメイン参照 *名前 か 型の直書き)。 どちらの変更も「定義域変更」として列挙する
function adef(x) { return _a5erNorm(TFC.s(x.domain) ? '*' + TFC.s(x.domain) : TFC.s(x.typeText)); }
function amap(e) { var m = {}; for (var i = 0; i < e.attrs.length; i++) { var k = akey(e.attrs[i]); if (k) m[k] = e.attrs[i]; } return m; }
var nAttr = 0, i;
for (i = 0; i < cur.entities.length; i++) nAttr += cur.entities[i].attrs.length;
if (!prev) return TFC.tf('edmhis.diff.summary', lang, [cur.entities.length, nAttr]);
var pm = {}, cm = {}, k;
for (i = 0; i < prev.entities.length; i++) { k = ekey(prev.entities[i]); if (k) pm[k] = prev.entities[i]; }
for (i = 0; i < cur.entities.length; i++) { k = ekey(cur.entities[i]); if (k) cm[k] = cur.entities[i]; }
var lines = [], added = [], removed = [];
for (k in cm) { if (cm.hasOwnProperty(k) && !pm[k]) added.push(elabel(cm[k])); }
for (k in pm) { if (pm.hasOwnProperty(k) && !cm[k]) removed.push(elabel(pm[k])); }
if (added.length) lines.push(TFC.t('edmhis.diff.entAdd', lang) + ': ' + added.join(', '));
if (removed.length) lines.push(TFC.t('edmhis.diff.entDel', lang) + ': ' + removed.join(', '));
for (k in cm) {
if (!cm.hasOwnProperty(k) || !pm[k]) continue;
var ca = amap(cm[k]), pa = amap(pm[k]), aAdd = [], aDel = [], aChg = [], ak;
for (ak in ca) {
if (!ca.hasOwnProperty(ak)) continue;
if (!pa[ak]) aAdd.push(alabel(ca[ak]));
else if (adef(ca[ak]) !== adef(pa[ak])) aChg.push(alabel(ca[ak]) + ' (' + (adef(pa[ak]) || '-') + ' → ' + (adef(ca[ak]) || '-') + ')');
}
for (ak in pa) { if (pa.hasOwnProperty(ak) && !ca[ak]) aDel.push(alabel(pa[ak])); }
var parts = [];
if (aAdd.length) parts.push(TFC.t('edmhis.diff.attrAdd', lang) + ' ' + aAdd.join(', '));
if (aDel.length) parts.push(TFC.t('edmhis.diff.attrDel', lang) + ' ' + aDel.join(', '));
if (aChg.length) parts.push(TFC.t('edmhis.diff.domChg', lang) + ' ' + aChg.join(', '));
if (parts.length) lines.push(elabel(cm[k]) + ': ' + parts.join(' / '));
}
if (!lines.length) return TFC.t('edmhis.diff.layoutOnly', lang);
var s = lines.join('\n');
return s.length > 20000 ? s.substring(0, 20000) + '…' : s;
}
TFC.edmModelDiffText = _edmModelDiffText;
/**
* ★Ver1.0.22 (No.232): EDM 履歴の「変更内容」を版のファイルから lang で作り直す (言語変換から呼ぶ)。 @return { total, updated, skipped }
* 版ごとの .a5er は history/ に複製してある (HIS_SRC_FILE)。 前の版 = 同じ EDM の直前の削除でない版。 読めない / 変わらない行は skipped
*/
TFC.regenEdmHistoryNotes = function (lang) {
var res = { total: 0, updated: 0, skipped: 0 };
if (!_edmHisTablesExist()) return res;
var thumb = _edmThumbnailBase();
var rows = TFC.selectPS('SELECT EDM_CD, REV_NO, CHANGE_KBN, HIS_SRC_FILE, CHANGE_NOTE FROM ' + EDM_HIS + ' ORDER BY EDM_CD, REV_NO', []);
var prevByCd = {}, i;
for (i = 0; i < rows.length; i++) {
var cd = TFC.s(rows[i]['EDM_CD']), rev = Number(TFC.s(rows[i]['REV_NO'])), kbn = TFC.s(rows[i]['CHANGE_KBN']), srcVal = TFC.s(rows[i]['HIS_SRC_FILE']);
if (kbn === 'D') { prevByCd[cd] = null; continue; }
res.total++;
var note = null;
try {
var curTxt = srcVal ? _edmCatReadSrc(thumb, srcVal) : null;
var prevTxt = prevByCd[cd] ? _edmCatReadSrc(thumb, prevByCd[cd]) : null;
note = curTxt ? (_edmModelDiffText(prevTxt, curTxt, lang) || null) : null;
} catch (eR) { note = null; }
if (srcVal) prevByCd[cd] = srcVal;
var oldNote = _uiLangClobToStr(rows[i]['CHANGE_NOTE']);
if (note == null || note === oldNote) { res.skipped++; continue; }
res.updated += TFC.updatePS('UPDATE ' + EDM_HIS + ' SET CHANGE_NOTE = ? WHERE EDM_CD = ? AND REV_NO = ?', [note, cd, rev]);
}
return res;
};
/**
* EDM の改訂履歴の追記。 @param opts { srcFuncId, userId, initial } @return { ins, upd, del, init, files, skipped }
*/
TFC.recordEdmHistory = function (opts) {
opts = opts || {};
var res = { ins: 0, upd: 0, del: 0, init: 0, files: 0, skipped: false };
if (!_edmHisTablesExist()) { res.skipped = true; return res; }
var thumb = _edmThumbnailBase();
var ctx = { src: _edmCatCut(TFC.s(opts.srcFuncId) || 'TFC', 64), actor: _hisActor(opts), initial: !!opts.initial, now: _hisNow(), since: opts.since || null }; // since: 確定後 JS の開始 (No.183)
var cur = TFC.selectPS('SELECT EDM_CD, ' + _EDM_HIS_COLS.join(', ') +
', CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE, MODIFY_COUNT' + (_edmHasModelCol() ? ', MODEL_FILE' : '') + ' FROM TLN_M_FUNC_EDM', []);
ctx.ref = _hisRefMillis(cur, ctx.since || ctx.now); // ★No.183 確認NG (2026-09-30): 既存判定の基準 = 現在行の最新 UPDATED_DATE (時差に依存しない)
var latest = TFC.selectPS('SELECT h.EDM_CD, h.REV_NO, h.CHANGE_KBN, h.' + _EDM_HIS_COLS.join(', h.') +
', h.SRC_HASH, h.HIS_SRC_FILE, h.HIS_SVG_FILE FROM ' + EDM_HIS + ' h INNER JOIN (SELECT EDM_CD, MAX(REV_NO) AS MAXREV FROM ' +
EDM_HIS + ' GROUP BY EDM_CD) m ON m.EDM_CD = h.EDM_CD AND m.MAXREV = h.REV_NO', []);
var last = {};
for (var li = 0; li < latest.length; li++) last[TFC.s(latest[li]['EDM_CD'])] = latest[li];
var names = ['EDM_CD'].concat(_HIS_META_COLS).concat(_EDM_HIS_COLS).concat(['SRC_HASH', 'HIS_SRC_FILE', 'HIS_SVG_FILE', 'CHANGE_NOTE']);
var longIdx = [];
for (var ni = 0; ni < names.length; ni++) longIdx.push(names[ni] === 'CHANGE_NOTE');
var lang = (typeof TFC.uiLang === 'function') ? TFC.uiLang() : 'ja';
function metaVals(kbn, rev, by, at, cols, mod) {
var who = _edmCatCut(TFC.s(ctx.actor), 50), prg = _edmCatCut(TFC.s(ctx.src), 50);
return [_JInt.valueOf(rev), kbn, _edmCatCut(TFC.s(by), 50), at, _hisYm(at), ctx.src,
_edmCatCut(cols.join(','), _HIS_COLS_MAX), _JInt.valueOf(0),
ctx.now, who, prg, ctx.now, who, prg];
}
function colVals(row) {
var out = [];
for (var ci = 0; ci < _EDM_HIS_COLS.length; ci++) {
var v = row[_EDM_HIS_COLS[ci]];
if (_EDM_HIS_COLS[ci] === 'SORT_NO') { out.push(v == null || TFC.s(v) === '' ? null : v); continue; }
v = TFC.s(v); out.push(v === '' ? null : v);
}
return out;
}
var seen = {};
for (var ri = 0; ri < cur.length; ri++) {
var row = cur[ri], cd = TFC.s(row['EDM_CD']);
if (!cd) continue;
seen[cd] = 1;
var prev = last[cd];
var modelVal = _edmModelVal(row); // Ver1.0.7: 版の複製・ハッシュ・変更内容は派生モデル (.a5er)
var srcPath = _edmSrcFullPath(thumb, modelVal);
var hash = _edmFileHash(srcPath);
var by = TFC.s(row['UPDATED_BY']) || TFC.s(row['CREATED_BY']) || ctx.actor;
var at = row['UPDATED_DATE'] || row['CREATED_DATE'] || ctx.now;
var kbn, rev, diff;
if (!prev || TFC.s(prev['CHANGE_KBN']) === 'D') {
kbn = (ctx.initial || _hisPreExisting(row, ctx.ref, ctx.since || ctx.now)) ? 'S' : 'I'; // ★Ver1.0.13 (No.183): 履歴の無い既存行は初期取込 (Ver1.0.22: 未更新の既存行も)
rev = prev ? Number(TFC.s(prev['REV_NO'])) + 1 : 1;
diff = [];
} else {
diff = _hisDiffCols(_EDM_HIS_COLS, row, prev);
if (hash && TFC.s(prev['SRC_HASH']) !== hash && diff.indexOf('SRC_FILE') < 0) diff.push('SRC_FILE');
if (diff.length === 0) continue;
kbn = 'U';
rev = Number(TFC.s(prev['REV_NO'])) + 1;
}
// 版のファイル (a5er + プレビュー svg) を history/ に複製。 DB 値は TALON の FILE 項目の形 (物理//元名)
var note = null;
try {
var curTxt = _edmCatReadSrc(thumb, modelVal);
var prevTxt = (prev && TFC.s(prev['CHANGE_KBN']) !== 'D' && TFC.s(prev['HIS_SRC_FILE'])) ? _edmCatReadSrc(thumb, prev['HIS_SRC_FILE']) : null;
note = _edmModelDiffText(prevTxt, curTxt, lang) || null;
} catch (eNote) { note = null; }
_hisWithRetry(EDM_HIS, 'EDM_CD', cd, rev, function (r) {
var hisSrc = null, hisSvg = null;
if (srcPath) {
var orig = _edmOrigName(modelVal) || (cd + '.a5er');
var physA = _EDM_HIS_DIR + '/TLN_M_FUNC_EDM_SRC_FILE_' + cd + '_r' + r + '.a5er';
if (_edmHisCopy(srcPath, thumb + '/' + physA)) { hisSrc = physA + '//' + orig; res.files++; }
var svgSrc = _edmPreviewPathFor(srcPath);
var physS = physA.replace(/\.a5er$/i, '.svg');
if (_edmHisCopy(svgSrc, thumb + '/' + physS)) { hisSvg = physS + '//' + orig.replace(/\.a5er$/i, '') + '.svg'; res.files++; }
}
_hisInsert(EDM_HIS, names,
[cd].concat(metaVals(kbn, r, by, at, diff, row['MODIFY_COUNT'])).concat(colVals(row)).concat([hash || null, hisSrc, hisSvg, note]),
longIdx);
});
res[kbn === 'S' ? 'init' : (kbn === 'I' ? 'ins' : 'upd')]++;
}
for (var dk in last) {
if (!last.hasOwnProperty(dk) || seen[dk]) continue;
var lp = last[dk];
if (TFC.s(lp['CHANGE_KBN']) === 'D') continue;
_hisInsert(EDM_HIS, names,
[dk].concat(metaVals('D', Number(TFC.s(lp['REV_NO'])) + 1, ctx.actor, ctx.now, [], null)).concat(colVals(lp))
.concat([TFC.s(lp['SRC_HASH']) || null, TFC.s(lp['HIS_SRC_FILE']) || null, TFC.s(lp['HIS_SVG_FILE']) || null, null]),
longIdx);
res.del++;
}
return res;
};
// [[EDM-HISTORY-MODULE-END]]
// [[SEARCH-MODULE-BEGIN]]
// ============================================================
// 全文検索 (Ver1.0.5): 出力した設計書群 (HTML 一式) をブラウザ側 JS で横断検索する。
// ・サーバ処理は無い (ZIP を展開した file:// でも、 サーバ側出力の THUMBNAIL 配下でも同じに動く)
// ・出力時に全 HTML を「アンカー (見出し / summary / id 付きブロック・行) 単位」に分割した索引を同梱する:
// search-index.js … 通常の本文 (機能名・項目・SQL・JS・備考・依存・ER・辞書・EDM …)
// search-index-lib.js … コードブックの「ライブラリ」ブロック (tfc-lib-N) の全文。 1 機能で 1MB を超える
// ことがあるので既定では対象外。 検索バーのチェックで加える (ユーザーが自由に切替)
// JSON ではなく JS (window.TFC_SEARCH_INDEX = …) にするのは、 file:// では fetch が使えず <script src> なら
// 読めるため。 初回検索時に遅延読込する (ページ表示は重くならない)
// ・各ページ: 見出し (h1-h4) と summary に id が無ければ tfcs-N を付与 (結果から該当箇所へ飛ぶアンカー)、
// <body> 直後に検索バー (入力欄 + ライブラリ切替 + 結果パネル)、 </body> 直前に検索 JS を差し込む
// ・操作: "/" キーで入力欄へ (placeholder に薄く案内)、 Enter で検索、 Esc で閉じる。 スペース区切りは AND、
// 大小文字・全角半角 (NFKC) は同一視。 結果クリックで該当ページへ遷移し、 タブ・折りたたみを開いて
// スクロール + 一致語を強調 (同一ページ内なら遷移せずに移動)
// ・エディションで出力しないページは entries に無いので索引にも入らない。 meta/ (Markdown) は対象外
// ============================================================
var SEARCH_INDEX_FILE = 'search-index.js';
var SEARCH_INDEX_LIB_FILE = 'search-index-lib.js';
var _SEARCH_CHUNK_MAX = 1500; // 1 チャンクの最大文字数 (長い SQL / JS は同じアンカーで分割)
// HTML 実体参照を戻す (出力は escapeHtml 由来なので名前付き 6 種 + 数値参照で足りる)
function _searchUnescape(s) {
return String(s).replace(/&(#x[0-9a-fA-F]+|#[0-9]+|amp|lt|gt|quot|apos|nbsp);/g, function (m, e) {
if (e === 'amp') return '&';
if (e === 'lt') return '<';
if (e === 'gt') return '>';
if (e === 'quot') return '"';
if (e === 'apos') return "'";
if (e === 'nbsp') return ' ';
var code = (e.charAt(1) === 'x' || e.charAt(1) === 'X') ? parseInt(e.substring(2), 16) : parseInt(e.substring(1), 10);
return isNaN(code) ? m : String.fromCharCode(code);
});
}
// 1 ページを 1 パスで走査: 見出し (h1-h4) / summary に id が無ければ tfcs-N を付与し、 アンカー単位の本文を切り出す。
// アンカー = 見出し・summary (id 付与) と、 id を持つ div / details / section / tr / table / article
// (コードブックの tfc-fn-N / tfc-sql-N / tfc-lib-N、 項目行 item-…、 タブの pane など既存の id をそのまま使う)。
// script / style / コメントは本文に入れない。 戻り: { html: id 付与後の HTML, chunks: [{id, title, text, lib}] }
function _searchScanPage(html) {
html = String(html);
var out = [], chunks = [], pos = 0, n = html.length, seq = 0;
var curId = '', curTitle = '', curLib = false, buf = [], titleBuf = null, titleTag = '', skipUntil = null;
function clean(parts) { return parts.join(' ').replace(/\s+/g, ' ').replace(/^ | $/g, ''); }
function flush() {
var text = clean(buf);
if (text && curId) {
for (var i = 0; i < text.length; i += _SEARCH_CHUNK_MAX) {
chunks.push({ id: curId, title: curTitle, text: text.substring(i, i + _SEARCH_CHUNK_MAX), lib: curLib });
}
}
buf = [];
}
while (pos < n) {
var lt = html.indexOf('<', pos);
if (lt < 0) lt = n;
if (lt > pos) {
var tx = html.substring(pos, lt);
out.push(tx);
if (!skipUntil) { var u = _searchUnescape(tx); buf.push(u); if (titleBuf) titleBuf.push(u); }
}
if (lt >= n) break;
if (html.substring(lt, lt + 4) === '<!--') {
var ce = html.indexOf('-->', lt + 4);
ce = ce < 0 ? n : ce + 3;
out.push(html.substring(lt, ce));
pos = ce;
continue;
}
var gt = html.indexOf('>', lt);
if (gt < 0) { out.push(html.substring(lt)); break; }
var tag = html.substring(lt, gt + 1);
pos = gt + 1;
var m = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/.exec(tag);
if (!m) { out.push(tag); continue; }
var closing = (m[1] === '/'), name = m[2].toLowerCase();
if (skipUntil) { out.push(tag); if (closing && name === skipUntil) skipUntil = null; continue; }
if (!closing && (name === 'script' || name === 'style')) {
out.push(tag);
if (tag.charAt(tag.length - 2) !== '/') skipUntil = name;
continue;
}
var isHead = (name === 'h1' || name === 'h2' || name === 'h3' || name === 'h4' || name === 'summary');
if (!closing) {
var idm = /\sid="([^"]*)"/.exec(tag);
var id = idm ? idm[1] : '';
if (isHead) {
if (!id) { id = 'tfcs-' + (++seq); tag = tag.replace(/^<([a-zA-Z0-9]+)/, '<$1 id="' + id + '"'); }
flush(); curId = id; curLib = (id.indexOf('tfc-lib-') === 0); titleBuf = []; titleTag = name;
} else if (id && (name === 'div' || name === 'details' || name === 'section' || name === 'tr' || name === 'table' || name === 'article')) {
flush(); curId = id; curLib = (id.indexOf('tfc-lib-') === 0);
} else if (name === 'div' && /\sclass="tfc-fn-head"/.test(tag)) {
// ★No.164: コードブックのブロック (tfc-fn-N / tfc-sql-N / tfc-lib-N) のタイトルは、 直前の見出し (件数一覧の最後 =
// 「共通ライブラリ」) ではなくブロック自身の見出し行 (種別バッジ + 名前 + 文字数) にする
titleBuf = []; titleTag = 'div';
}
out.push(tag);
} else {
out.push(tag);
if (titleBuf && name === titleTag) { curTitle = clean(titleBuf); titleBuf = null; }
}
}
flush();
return { html: out.join(''), chunks: chunks };
}
var _SEARCH_CSS =
'.tfcs-bar{font-family:"Segoe UI",Meiryo,sans-serif;background:#1e293b;color:#e2e8f0;padding:6px 12px;position:relative;z-index:9000;box-sizing:border-box}' +
'.tfcs-form{display:flex;align-items:center;gap:10px;max-width:1280px;margin:0 auto}' +
'.tfcs-brand{font-weight:600;font-size:12px;color:#94a3b8;white-space:nowrap}' +
'.tfcs-q{flex:1;min-width:160px;padding:6px 10px;border:1px solid #475569;border-radius:6px;background:#0f172a;color:#f1f5f9;font-size:13px;box-sizing:border-box}' +
'.tfcs-q::placeholder{color:#64748b}' +
'.tfcs-q:focus{outline:2px solid #6366f1;border-color:#6366f1}' +
'.tfcs-lib{font-size:12px;color:#cbd5e1;white-space:nowrap;cursor:pointer}' +
'.tfcs-panel{position:absolute;left:0;right:0;top:100%;max-height:70vh;overflow:auto;background:#fff;color:#1e293b;border-bottom:2px solid #6366f1;box-shadow:0 8px 24px rgba(0,0,0,.25)}' +
'.tfcs-panel[hidden]{display:none}' +
'.tfcs-inner{max-width:1280px;margin:0 auto;padding:8px 12px 14px}' +
'.tfcs-stat{font-size:12px;color:#64748b;padding:4px 0 8px}' +
'.tfcs-page{font-weight:600;font-size:13px;margin:10px 0 4px;color:#312e81}' +
'.tfcs-page span{font-weight:400;color:#64748b}' +
'.tfcs-hit{display:block;padding:5px 8px;border-radius:4px;text-decoration:none;color:#1e293b;font-size:12.5px;border:1px solid transparent;line-height:1.5}' +
'.tfcs-hit:hover{background:#eef2ff;border-color:#c7d2fe}' +
'.tfcs-sec{color:#4f46e5;font-weight:600;margin-right:8px}' +
'.tfcs-snip{color:#475569}' +
'.tfcs-panel mark,mark.tfcs-mark{background:#fde68a;color:inherit;padding:0 1px}' +
'.tfcs-more{font-size:12px;color:#64748b;padding-top:6px}' +
'.tfcs-close{float:right;cursor:pointer;color:#64748b;font-size:12px;padding:4px 0}' +
'.tfcs-flash{outline:3px solid #f59e0b;outline-offset:2px}' +
/* 戻るボタンは画面右下に固定。 右隣の × (.tfcs-back-x) で消せる (Ver1.0.10) — 2 つで 1 つの丸いピルに見えるよう左右の角だけ丸める */
'.tfcs-back,.tfcs-back-x{position:fixed;bottom:18px;z-index:9001;font-size:13px;line-height:1.3;color:#e0e7ff;background:#312e81;border:1px solid #6366f1;padding:8px 14px;cursor:pointer;white-space:nowrap;font-family:"Segoe UI",Meiryo,sans-serif;box-shadow:0 4px 14px rgba(0,0,0,.35)}' +
'.tfcs-back{right:50px;border-radius:999px 0 0 999px;border-right:none}' +
'.tfcs-back-x{right:18px;border-radius:0 999px 999px 0;padding-left:9px;padding-right:11px}' +
'.tfcs-back:hover,.tfcs-back-x:hover{background:#3730a3}' +
'.tfcs-back[hidden],.tfcs-back-x[hidden]{display:none}' +
'.tfcs-hit.tfcs-cur{background:#fef3c7;border-color:#f59e0b}';
// ブラウザで動く検索 JS (ES5)。 文言は差し込み時に TFCS_L として先頭に置く
var _SEARCH_CLIENT_JS = [
"(function(){",
"var q=document.getElementById('tfcsQ'),panel=document.getElementById('tfcsPanel'),inner=document.getElementById('tfcsInner'),lib=document.getElementById('tfcsLib'),form=document.getElementById('tfcsForm'),bar=document.getElementById('tfcsBar'),back=document.getElementById('tfcsBack'),backX=document.getElementById('tfcsBackX');",
"if(!q||!panel||!inner||!form||!bar)return;",
"var IDX=null,LIB=null,loading=false,normCache=[],normCacheLib=[];",
"function norm(s){s=String(s);try{s=s.normalize('NFKC');}catch(e){}return s.toLowerCase();}",
"function esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g,'"');}",
"function fmt(t,a){return String(t).replace(/\\{(\\d+)\\}/g,function(m,i){return a[+i];});}",
"function show(h){inner.innerHTML=h;panel.hidden=false;}",
"function hide(){panel.hidden=true;}",
"function loadScript(src,done,fail){var s=document.createElement('script');s.src=src;s.onload=done;s.onerror=fail;document.head.appendChild(s);}",
"function ensure(cb){",
"var needLib=!!(lib&&lib.checked);",
"if(IDX&&(!needLib||LIB)){cb();return;}",
"if(loading)return;loading=true;show('<div class=\"tfcs-stat\">'+esc(TFCS_L.loading)+'</div>');",
"var pending=0;function one(){pending--;if(pending<=0){loading=false;cb();}}",
"function bad(){loading=false;show('<div class=\"tfcs-stat\">'+esc(TFCS_L.err)+'</div>');}",
"if(!IDX){pending++;loadScript('search-index.js',function(){IDX=window.TFC_SEARCH_INDEX||null;if(!IDX){bad();return;}one();},bad);}",
"if(needLib&&!LIB){pending++;loadScript('search-index-lib.js',function(){LIB=window.TFC_SEARCH_INDEX_LIB||{chunks:[]};one();},bad);}",
"}",
"function tokens(s){var t=norm(s).split(/\\s+/),o=[];for(var i=0;i<t.length;i++)if(t[i])o.push(t[i]);return o;}",
"function flagsOf(ns,toks){var flags=null;for(var t=0;t<toks.length;t++){var k=0,tk=toks[t];while(tk&&(k=ns.indexOf(tk,k))>=0){flags=flags||[];for(var j=k;j<k+tk.length;j++)flags[j]=1;k+=tk.length;}}return flags;}",
"function mark(s,toks){var ns=norm(s);if(ns.length!==s.length)return esc(s);var flags=flagsOf(ns,toks);if(!flags)return esc(s);",
"var out='',i=0;while(i<s.length){var j=i;while(j<s.length&&!!flags[j]===!!flags[i])j++;var seg=esc(s.substring(i,j));out+=flags[i]?'<mark>'+seg+'</mark>':seg;i=j;}return out;}",
"function snippet(text,toks){var nt=norm(text),p=-1;for(var i=0;i<toks.length;i++){var k=nt.indexOf(toks[i]);if(k>=0&&(p<0||k<p))p=k;}if(p<0)p=0;",
"var st=Math.max(0,p-50),en=Math.min(text.length,p+130);return (st>0?'…':'')+mark(text.substring(st,en),toks)+(en<text.length?'…':'');}",
"function here(){var p=location.pathname.split('/').pop();try{p=decodeURIComponent(p);}catch(e){}return p;}",
// 戻り先の状態 (語 / ライブラリ切替 / 押した結果の番号 / 一覧のスクロール位置 / 検索したページ) は sessionStorage に持ち、
// どのページでも「検索結果に戻る」ボタン (#tfcsBack、 画面右下に固定) で同じ一覧を同じ位置に開き直す。
// 検索したページへブラウザの戻るで帰ったときは自動で開く (生成ページには入れない = 全ページの JS を膨らませない)
"function saveRet(idx){try{sessionStorage.setItem('tfcs-ret',JSON.stringify({q:q.value,lib:!!(lib&&lib.checked),idx:idx,top:panel.scrollTop,page:here()}));}catch(e){}}",
"function loadRet(){try{var s=sessionStorage.getItem('tfcs-ret');return s?JSON.parse(s):null;}catch(e){return null;}}",
"function showBack(){if(!back)return;var st=loadRet();back.hidden=!st;if(backX)backX.hidden=!st;if(st)back.title=st.q;}",
// × = 戻り先の状態を捨てて両方のボタンを消す (Ver1.0.10)。 次に結果を押せばまた保存されて出る
"function dismissBack(){try{sessionStorage.removeItem('tfcs-ret');}catch(e){}if(back)back.hidden=true;if(backX)backX.hidden=true;}",
"function restore(){var st=loadRet();if(!st)return;q.value=st.q;if(lib)lib.checked=!!st.lib;",
"search(function(){var hits=inner.querySelectorAll('a.tfcs-hit'),a=hits[st.idx]||null;panel.scrollTop=st.top||0;",
"if(a){a.classList.add('tfcs-cur');var r=a.getBoundingClientRect(),pr=panel.getBoundingClientRect();if(r.top<pr.top||r.bottom>pr.bottom)a.scrollIntoView({block:'center'});}});}",
"function search(after){var toks=tokens(q.value);if(!toks.length){hide();return;}",
"ensure(function(){",
"var res=[],hitPages={};",
"function scan(arr,cache){for(var i=0;i<arr.length;i++){var c=arr[i],nt=cache[i];if(nt==null){nt=cache[i]=norm(c[2]+' '+c[3]);}",
"var ok=true;for(var t=0;t<toks.length;t++){if(nt.indexOf(toks[t])<0){ok=false;break;}}if(ok){res.push(c);hitPages[c[0]]=1;}}}",
"scan(IDX.chunks,normCache);if(lib&&lib.checked&&LIB)scan(LIB.chunks,normCacheLib);",
"var np=0;for(var k in hitPages)if(hitPages.hasOwnProperty(k))np++;",
"if(!res.length){show('<span class=\"tfcs-close\" id=\"tfcsClose\">'+esc(TFCS_L.close)+'</span><div class=\"tfcs-stat\">'+esc(TFCS_L.none)+'</div>');bindClose();return;}",
"var MAX=300,h='<span class=\"tfcs-close\" id=\"tfcsClose\">'+esc(TFCS_L.close)+'</span><div class=\"tfcs-stat\">'+esc(fmt(TFCS_L.hits,[res.length,np]))+'</div>',last=-1;",
"for(var i=0;i<res.length&&i<MAX;i++){var c=res[i],pg=IDX.pages[c[0]];",
"if(c[0]!==last){h+='<div class=\"tfcs-page\">'+esc(pg.t)+' <span>('+esc(pg.f)+')</span></div>';last=c[0];}",
"h+='<a class=\"tfcs-hit\" href=\"'+esc(encodeURI(pg.f))+'#'+esc(c[1])+'\" data-f=\"'+esc(pg.f)+'\" data-id=\"'+esc(c[1])+'\"><span class=\"tfcs-sec\">'+mark(c[2]||'',toks)+'</span><span class=\"tfcs-snip\">'+snippet(c[3],toks)+'</span></a>';}",
"if(res.length>MAX)h+='<div class=\"tfcs-more\">'+esc(fmt(TFCS_L.more,[MAX]))+'</div>';",
"show(h);bindClose();",
"var links=inner.querySelectorAll('a.tfcs-hit');for(var li=0;li<links.length;li++){(function(a,idx){a.addEventListener('click',function(ev){",
"try{sessionStorage.setItem('tfcs-q',q.value);}catch(e){}saveRet(idx);",
"if(a.getAttribute('data-f')===here()){ev.preventDefault();hide();showBack();try{history.replaceState(null,'','#'+a.getAttribute('data-id'));}catch(e2){}goTo(a.getAttribute('data-id'),q.value);}});})(links[li],li);}",
"if(after)after();",
"});}",
"function bindClose(){var cl=document.getElementById('tfcsClose');if(cl)cl.onclick=hide;}",
"function goTo(id,query){var tgt=document.getElementById(id);if(!tgt)return;",
"var p=tgt;while(p){var tn=p.tagName?p.tagName.toLowerCase():'';",
"if(tn==='details')p.open=true;",
"if(p.classList&&p.classList.contains('tfc-tab-pane')){var pid=p.id||'';var tab=document.querySelector('.tfc-tabs .tfc-tab[data-tab=\"'+pid.replace('tfc-pane-','')+'\"]');",
"if(tab){var tabs=document.querySelectorAll('.tfc-tabs .tfc-tab');for(var ti=0;ti<tabs.length;ti++)tabs[ti].classList.remove('tfc-tab-active');tab.classList.add('tfc-tab-active');",
"var panes=document.querySelectorAll('.tfc-tab-pane');for(var pi=0;pi<panes.length;pi++)panes[pi].style.display='none';p.style.display='block';}}",
"if(p.classList&&p.classList.contains('tfc-item-detail-row'))p.style.display='';",
"p=p.parentElement;}",
"var scope=tgt,tn2=tgt.tagName.toLowerCase();",
"if(tn2==='summary'||/^h[1-4]$/.test(tn2))scope=tgt.parentElement||tgt;",
"if(query)highlight(scope,tokens(query));",
"setTimeout(function(){tgt.scrollIntoView({block:'center'});tgt.classList.add('tfcs-flash');setTimeout(function(){tgt.classList.remove('tfcs-flash');},2500);},60);",
"}",
"function highlight(root,toks){if(!toks.length||!document.createTreeWalker)return;var count=0,walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,null,false),nodes=[];",
"while(walker.nextNode())nodes.push(walker.currentNode);",
"for(var i=0;i<nodes.length&&count<400;i++){var nd=nodes[i],s=nd.nodeValue;if(!s||!s.replace(/\\s+/g,''))continue;var pe=nd.parentElement;if(!pe||/^(script|style|mark|textarea)$/i.test(pe.tagName))continue;",
"var ns=norm(s);if(ns.length!==s.length)continue;var flags=flagsOf(ns,toks);if(!flags)continue;",
"var frag=document.createDocumentFragment(),a=0;",
"while(a<s.length){var b=a;while(b<s.length&&!!flags[b]===!!flags[a])b++;var seg=s.substring(a,b);",
"if(flags[a]){var m=document.createElement('mark');m.className='tfcs-mark';m.textContent=seg;frag.appendChild(m);count++;}else frag.appendChild(document.createTextNode(seg));a=b;}",
"pe.replaceChild(frag,nd);}}",
"form.addEventListener('submit',function(ev){ev.preventDefault();search();});",
"q.addEventListener('keydown',function(ev){if(ev.key==='Escape'){ev.preventDefault();hide();q.blur();}});",
/* ★No.165: input type=search はブラウザが Esc で入力欄を消す (既定動作) → preventDefault で「閉じる」だけに揃える。
★No.166: 「検索結果に戻る」で開き直した後は入力欄にフォーカスが無い → document で Esc を拾い、 結果が開いていれば閉じる */
"document.addEventListener('keydown',function(ev){if(ev.key==='Escape'&&!panel.hidden){ev.preventDefault();hide();}});",
"if(lib)lib.addEventListener('change',function(){if(q.value)search();});",
"document.addEventListener('keydown',function(ev){if(ev.key!=='/'||ev.ctrlKey||ev.altKey||ev.metaKey)return;var t=ev.target,tn=(t&&t.tagName)?t.tagName.toLowerCase():'';",
"if(tn==='input'||tn==='textarea'||tn==='select'||(t&&t.isContentEditable))return;ev.preventDefault();q.focus();q.select();});",
"document.addEventListener('click',function(ev){if(!panel.hidden&&!bar.contains(ev.target))hide();});",
"if(back)back.addEventListener('click',function(){try{window.scrollTo(0,0);}catch(e){}restore();});", // Ver1.0.22 (No.196): 画面下から押しても変化が見えるよう先頭へ
"if(backX)backX.addEventListener('click',dismissBack);",
"showBack();",
"try{var st0=loadRet(),nav=(window.performance&&performance.getEntriesByType)?performance.getEntriesByType('navigation')[0]:null;",
"if(st0&&st0.page===here()&&nav&&nav.type==='back_forward'&&!sessionStorage.getItem('tfcs-q')){setTimeout(restore,150);}}catch(e){}",
"try{var sq=sessionStorage.getItem('tfcs-q');if(sq&&location.hash.length>1){q.value=sq;sessionStorage.removeItem('tfcs-q');",
"var go=function(){goTo(location.hash.substring(1),sq);};",
"if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',function(){setTimeout(go,80);});else setTimeout(go,80);",
"window.addEventListener('load',function(){setTimeout(function(){var t=document.getElementById(location.hash.substring(1));if(t)t.scrollIntoView({block:'center'});},300);});}}catch(e){}",
"})();"
].join('\n');
function _searchBarHtml(l) {
return '<style>' + _SEARCH_CSS + '</style>\n' +
'<div class="tfcs-bar" id="tfcsBar">' +
'<form class="tfcs-form" id="tfcsForm" autocomplete="off">' +
'<span class="tfcs-brand">' + TFC.escapeHtml(TFC.t('search.title', l)) + '</span>' +
'<input class="tfcs-q" id="tfcsQ" type="search" placeholder="' + TFC.escapeAttr(TFC.t('search.placeholder', l)) +
'" aria-label="' + TFC.escapeAttr(TFC.t('search.title', l)) + '">' +
'<label class="tfcs-lib"><input type="checkbox" id="tfcsLib"> ' + TFC.escapeHtml(TFC.t('search.lib', l)) + '</label>' +
'</form>' +
/* ジャンプ後はページ先頭のバーが画面外になるので、 戻るボタンは画面右下に固定 (状態が無ければ非表示) */
'<button type="button" class="tfcs-back" id="tfcsBack" hidden>' + TFC.escapeHtml(TFC.t('search.back', l)) + '</button>' +
/* × で戻るボタンを消す (戻り先の状態も捨てるので、 他のページへ移っても出てこない。 次に結果を押せばまた出る) */
'<button type="button" class="tfcs-back-x" id="tfcsBackX" hidden title="' + TFC.escapeAttr(TFC.t('search.backClose', l)) +
'" aria-label="' + TFC.escapeAttr(TFC.t('search.backClose', l)) + '">×</button>' +
'<div class="tfcs-panel" id="tfcsPanel" hidden><div class="tfcs-inner" id="tfcsInner"></div></div>' +
'</div>\n';
}
function _searchClientJs(l) {
var L = { loading: TFC.t('search.loading', l), err: TFC.t('search.loadError', l), none: TFC.t('search.none', l),
hits: TFC.t('search.hits', l), more: TFC.t('search.more', l), close: TFC.t('search.close', l) };
return 'var TFCS_L=' + JSON.stringify(L) + ';\n' + _SEARCH_CLIENT_JS;
}
// 検索バーを <body> 直後、 検索 JS を </body> 直前 (既存の末尾 script の後 = DOMContentLoaded の順序を保つ) に差し込む
function _searchInjectUi(html, l) {
var bm = /<body\b[^>]*>/i.exec(html);
if (!bm) return html;
var at = bm.index + bm[0].length;
var head = html.substring(0, at), rest = html.substring(at);
var script = '<script>' + _searchClientJs(l) + '</script>\n';
var tail = rest.lastIndexOf('</body>');
if (tail < 0) return head + '\n' + _searchBarHtml(l) + rest + script;
return head + '\n' + _searchBarHtml(l) + rest.substring(0, tail) + script + rest.substring(tail);
}
// JS ファイルとして安全な JSON (U+2028/2029 は古いエンジンで文字列リテラルを壊す)
function _searchJsonJs(obj) {
return JSON.stringify(obj).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
}
/**
* 成果物一式 (zipEntries) の HTML にアンカー id と検索バーを差し込み、 索引ファイルのエントリを返す。
* entries の HTML は content を書き換える (副作用)。 対象 = ルート直下の *.html (meta/ は Markdown で対象外)。
* @returns {Array<{name, content}>} [search-index.js, search-index-lib.js] (呼び出し側で zipEntries に push)
*/
TFC.searchInject = function (entries, lang) {
var l = (lang === 'en') ? 'en' : 'ja';
var pages = [], chunks = [], libChunks = [];
for (var i = 0; i < entries.length; i++) {
var e = entries[i];
var nm = String(e.name || '');
if (!/\.html$/i.test(nm) || nm.indexOf('/') >= 0 || typeof e.content !== 'string') continue;
var scanned = _searchScanPage(e.content);
var tm = /<title>([\s\S]*?)<\/title>/i.exec(e.content);
var pi = pages.length;
pages.push({ f: nm, t: tm ? _searchUnescape(tm[1]).replace(/\s+/g, ' ').replace(/^ | $/g, '') : nm });
for (var c = 0; c < scanned.chunks.length; c++) {
var ch = scanned.chunks[c];
(ch.lib ? libChunks : chunks).push([pi, ch.id, ch.title, ch.text]);
}
e.content = _searchInjectUi(scanned.html, l);
}
return [
{ name: SEARCH_INDEX_FILE, content: 'window.TFC_SEARCH_INDEX=' + _searchJsonJs({ v: 1, lang: l, pages: pages, chunks: chunks }) + ';\n' },
{ name: SEARCH_INDEX_LIB_FILE, content: 'window.TFC_SEARCH_INDEX_LIB=' + _searchJsonJs({ v: 1, chunks: libChunks }) + ';\n' }
];
};
TFC._searchScanPage = _searchScanPage;
// [[SEARCH-MODULE-END]]
// ============================================================
// ★Ver1.0.23 (D): 知識グラフ エクスプローラ (Graph.html)
// ============================================================
// graph-data.js (window.CW_GRAPH = meta/graph/graph.json / window.CW_ONTOLOGY = meta/graph/ontology.json) を読んで、 起点の近傍を 系譜 (レーン配置) か
// 関係図 (力学モデル) で描く。 描画 JS の正本は src/common/client-js/graph-explorer.js (tools/embed_graph_explorer.py が下のブロックに埋め込む)。
// 文言は graph.* (出力言語に追随)。 ページは全プランに同梱し、 中身はグラフの範囲 (エディション) に従う。
// [[GRAPH-EXPLORER-JS-BEGIN]]
// 知識グラフ エクスプローラ (Graph.html) のクライアント JS。 正本 = src/common/client-js/graph-explorer.js、 tools/embed_graph_explorer.py が生成 (手で編集しない)
var _GRAPH_EXPLORER_JS = [
"/* Commonweal 知識グラフ エクスプローラ (Ver1.0.23 D)。 ES5、 外部ライブラリ無し。",
" * 設計書 ZIP の Graph.html に埋め込まれ、 graph-data.js (window.CW_GRAPH = meta/graph/graph.json と同じ、 window.CW_ONTOLOGY = meta/graph/ontology.json) を読む。",
" * ・系譜 (layered): 文脈 → EDM → エンティティ → 属性 → 業務データ辞書 → テーブル → 列 → 機能 の 8 レーンに左から右へ並べる (カタログ製品の系譜図と同じ読み方。 2026-10-12〜13 にレーンを細分化)",
" * ・関係図 (force): ばね + 反発の力学モデル (近傍を眺める。 ノード数に上限)",
" * ・起点を 1 つ決めて深さ N の近傍を取り、 エッジの種類で絞り込む。 ノードを押すと詳細、 ダブルクリックで起点にする、 詳細の url で設計書",
" * ・★Ver1.0.23 第 3 段 (2026-10-07): 間隔のプリセット (自動 / 密 / 標準 / 広い / 最広 = spacing)、 箱の大きさ = 関係の数 (sizeBy: none / local / global)、",
" * 末端の畳み込み (bundleLeaves: 同じ中心に同じ関係で付く同じ種類の末端が 6 つ以上なら「種類 ×N」の 1 箱にまとめ、 押すと展開)。 関係図では導出した関係を既定オフ。",
" * このファイルは tools/embed_graph_explorer.py で TLN_FUNC_DOC_COMMON.server.js の _GRAPH_EXPLORER_JS に文字列として埋め込む (正本はこちら)。",
" * レイアウトと描画は DOM に依存しない純関数 (CWG.index / neighborhood / bundleLeaves / nodeSizes / layoutLayered / layoutForce / renderSvg) にして Node で回帰する。",
" */",
"(function (root) {",
" 'use strict';",
" var CWG = {};",
" // ★2026-10-12 (テスター要望): EDM (モデル) を独立のレーンに (6 レーン)。 ★2026-10-13 (ユーザー指示): 並びは 文脈 → EDM → エンティティ・属性 → 業務データ辞書 → 物理 DB → 機能",
" // (業務データ辞書は EDM 属性の宣言と物理列の照合を結ぶ層なので、 モデルと物理 DB の間に置く)。",
" // EDM の色はエンティティの紫と見分けやすい藍色に。 レーン見出しの下にそのレーンに入る種類の名前を添える (「文脈」= プロジェクト / 責任部門 / 業務分類)。",
" // ★2026-10-13 (ユーザー指示): 8 レーン = 文脈 → EDM → エンティティ → 属性 → 業務データ辞書 → テーブル → 列 → 機能。 辞書レーンはデータドメインだけ",
" // (物理属性名は照合のキーなので既定で隠す = HIDE_DEFAULT。 凡例で出せる)。 テーブル・列は「論理名 (物理名)」で表示 (displayLabel)。",
" // 深さの広げ方: 導出した関係は起点からの 1 本目だけ (inferredFromStartOnly)、 文脈 (HUB_TYPES) は通り抜けない (hubTypes) を既定に。",
" // ★2026-10-14 (第 10 段、 ユーザー決定): 入れ物の中身へ広がらない (containersFromStartOnly、 既定 ON)。 入れ物の関係 (CONTAIN_ALL) は中身から入れ物へは上がる (文脈) が、",
" // 入れ物から別の中身へは起点が入れ物のときだけ下りる (商品コード → 受注 (エンティティ) は出るが、 受注の他の属性 = 兄弟は出ない。 深さは幅優先で向きを問わないので、",
" // 入れ物を折り返すと兄弟に広がっていた)。",
" var LANES = ['context', 'edm', 'entity', 'attribute', 'dictionary', 'table', 'column', 'function'];",
" var NL = LANES.length;",
" var LANE_OF = { Project: 0, Dept: 0, Category: 0, Edm: 1, EdmEntity: 2, SubtypeNode: 2, EdmAttribute: 3, DataDomain: 4, PhysAttr: 4, Table: 5, Column: 6, Function: 7, Block: 7, Item: 7 };",
" var HUB_TYPES = { Project: 1, Dept: 1, Category: 1 }; // 文脈 = 多くのものが繋がるハブ (既定では通り抜けない)",
" var CONTAIN = { hasBlock: 1, hasItem: 1 }; // 内包の関係 (機能 ⊃ ブロック ⊃ 画面項目)。 系譜では線を描かず、 入れ物の枠の中に入れ子で描く (案 C、 2026-10-13)",
" var CONTAIN_ALL = { hasEntity: 1, hasAttribute: 1, hasBlock: 1, hasItem: 1, hasColumn: 1, hasPhysAttr: 1 }; // 入れ物 → 中身 の関係すべて (EDM ⊃ エンティティ ⊃ 属性、 機能 ⊃ ブロック ⊃ 項目、 テーブル ⊃ 列、 データドメイン ⊃ 物理属性)。 近傍の「入れ物の中身へ広がらない」が見る (2026-10-14)",
" var NEST_INDENT = 14, NEST_PAD = 6; // 入れ子: 子の字下げ / 枠の内側の余白",
" var HIDE_DEFAULT = ['PhysAttr']; // 既定で隠す種類 (辞書の物理属性名 = 照合のキー。 データドメイン → 列 は照合の線で直接つながる)",
" var TYPE_COLOR = { Function: '#2563eb', Block: '#60a5fa', Item: '#93c5fd', Table: '#059669', Column: '#6ee7b7', DataDomain: '#d97706', PhysAttr: '#fbbf24',",
" Edm: '#3730a3', EdmEntity: '#8b5cf6', EdmAttribute: '#c4b5fd', SubtypeNode: '#a78bfa', Category: '#64748b', Dept: '#78716c', Project: '#475569' };",
" var SUB_RANK = { Project: 0, Dept: 1, Category: 2, DataDomain: 0, PhysAttr: 1, Edm: 0, EdmEntity: 0, SubtypeNode: 1, EdmAttribute: 0, Table: 0, Column: 0, Function: 0, Block: 1, Item: 2 };",
" var NODE_H = 24, LANE_GAP = 110, ROW_GAP = 10, PAD = 30, LANE_TOP = 48; // LANE_TOP = 系譜の上端 (レーン名 + 種類の小見出しのぶん)",
" function laneTypes(lane) { var a = [], k; for (k in LANE_OF) if (has(LANE_OF, k) && LANE_OF[k] === lane) a.push(k); return a; } // レーンに入る種類 (定義順)",
" function displayLabel(n) { // 箱の表示名。 テーブル・列は「論理名 (物理名)」(論理名があるとき。 2026-10-13)",
" if (!n) return '';",
" var lbl = String(n.label || n.id || '');",
" if ((n.type === 'Table' || n.type === 'Column') && n.props && n.props.logicalName && String(n.props.logicalName) !== lbl) return String(n.props.logicalName) + ' (' + lbl + ')';",
" if (n.type === 'Function' && n.props && n.props.funcId && String(n.props.funcId) !== lbl) return lbl + ' (' + String(n.props.funcId) + ')';",
" if (n.type === 'Block' && n.props && n.props.funcName && n.props.no != null) return String(n.props.funcName) + ': ' + String(n.props.no) + (n.props.title ? ': ' + String(n.props.title) : ''); // ブロックは「機能名: No: タイトル」(ユーザー指示 2026-10-13。 機能を隠しても機能が分かる) // 機能は「機能名 (機能ID)」(ユーザー指示 2026-10-13)",
" return lbl;",
" }",
" CWG.HUB_TYPES = HUB_TYPES; CWG.HIDE_DEFAULT = HIDE_DEFAULT; CWG.displayLabel = displayLabel; CWG.CONTAIN = CONTAIN; CWG.CONTAIN_ALL = CONTAIN_ALL; CWG.NEST = { indent: NEST_INDENT, pad: NEST_PAD };",
" // 間隔のプリセット: k = 力学モデルの基準距離と描画領域の倍率、 gap = 重なりをほどく余白 (px)、 lane / row = 系譜のレーン間隔・行間隔の倍率",
" var SPACING = { compact: { k: 0.8, gap: 6, lane: 0.75, row: 0.7 }, normal: { k: 1, gap: 8, lane: 1, row: 1 }, wide: { k: 1.4, gap: 14, lane: 1.4, row: 1.5 }, widest: { k: 1.9, gap: 24, lane: 1.9, row: 2.1 } };",
" var AUTO_WIDE_NODES = 60; // 自動: ノードがこれより多ければ「広い」",
" function has(o, k) { return Object.prototype.hasOwnProperty.call(o, k); }",
" function keys(o) { var a = [], k; for (k in o) if (has(o, k)) a.push(k); return a; }",
" function esc(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"'); }",
" function textW(s) { // 文字幅の概算 (px、 10.5px の文字): 全角 11 / 半角 6.5",
" var w = 0, i, c; s = String(s == null ? '' : s);",
" for (i = 0; i < s.length; i++) { c = s.charCodeAt(i); w += (c > 255) ? 11 : 6.5; }",
" return w;",
" }",
" function spacingOf(opts, n) { var s = opts && opts.spacing; if (!s || s === 'auto' || !has(SPACING, s)) s = (n > AUTO_WIDE_NODES) ? 'wide' : 'normal'; return SPACING[s]; }",
" function nodeOf(sub, idx, id) { return (sub && sub.virtual && has(sub.virtual, id)) ? sub.virtual[id] : idx.nodes[id]; } // 畳み込みの仮想ノードも引ける",
" function edgeKey(e) { return e.from + '\\t' + e.to + '\\t' + e.type; }",
" function sortEdges(edges) { edges.sort(function (a, b) { var ka = edgeKey(a), kb = edgeKey(b); return ka < kb ? -1 : (ka > kb ? 1 : 0); }); return edges; }",
" CWG.LANES = LANES; CWG.LANE_OF = LANE_OF; CWG.TYPE_COLOR = TYPE_COLOR; CWG.SPACING = SPACING; CWG.spacingOf = spacingOf; CWG.nodeOf = nodeOf;",
"",
" // ---- 索引: id → ノード、 出入りのエッジ、 次数 (導出を除く = 設計書全体での関わりの大きさ) ----",
" CWG.index = function (graph) {",
" var idx = { nodes: {}, out: {}, inn: {}, byType: {}, edgeTypes: {}, order: [], inferred: 0, deg: {}, maxDeg: 0 }, i, n, e;",
" for (i = 0; i < graph.nodes.length; i++) {",
" n = graph.nodes[i]; idx.nodes[n.id] = n; idx.order.push(n.id);",
" if (!idx.byType[n.type]) idx.byType[n.type] = []; idx.byType[n.type].push(n.id);",
" }",
" for (i = 0; i < graph.edges.length; i++) {",
" e = graph.edges[i];",
" if (!idx.nodes[e.from] || !idx.nodes[e.to]) continue;",
" if (!idx.out[e.from]) idx.out[e.from] = []; idx.out[e.from].push(e);",
" if (!idx.inn[e.to]) idx.inn[e.to] = []; idx.inn[e.to].push(e);",
" idx.edgeTypes[e.type] = (idx.edgeTypes[e.type] || 0) + 1;",
" if (e.inferred) idx.inferred++;",
" else { idx.deg[e.from] = (idx.deg[e.from] || 0) + 1; idx.deg[e.to] = (idx.deg[e.to] || 0) + 1; }",
" }",
" for (i = 0; i < idx.order.length; i++) if ((idx.deg[idx.order[i]] || 0) > idx.maxDeg) idx.maxDeg = idx.deg[idx.order[i]];",
" for (i = 0; i < graph.edges.length; i++) { // ブロックの表示名「機能名: No: タイトル」のために、 入れ物の機能の名前をブロックに持たせる (データは変えない = 表示用の props)",
" e = graph.edges[i]; if (e.type !== 'hasBlock' || e.inferred) continue;",
" var bn = idx.nodes[e.to], fnn = idx.nodes[e.from];",
" if (bn && fnn && bn.type === 'Block' && fnn.type === 'Function') { if (!bn.props) bn.props = {}; if (bn.props.funcName == null) bn.props.funcName = String(fnn.label || fnn.id); }",
" }",
" return idx;",
" };",
"",
" // ---- 近傍: 起点から深さ depth まで (幅優先)。 edgeTypes = 許すエッジ種類の集合 (null = 全部)、 direction = 'both' | 'out' | 'in'、 includeInferred = false で導出辺を除く ----",
" // ★2026-10-13: inferredFromStartOnly = true で導出した関係は起点から出る 1 本目だけに使う (2 本目以降の広がりには使わない = 「顧客納期を扱う機能」は出るが",
" // 「その機能が扱う別の概念」までは出ない)。 hubTypes = { Dept: 1, … } の種類のノードは起点でない限り先へ広げない (責任部門 → 他の辞書 の広がりを止める)。",
" // ★2026-10-14: containersFromStartOnly = true で入れ物の関係 (CONTAIN_ALL) を入れ物から中身へ下りる向きには起点からだけ使う (中身 → 入れ物 は常に可 = 文脈)。",
" CWG.neighborhood = function (idx, startId, opts) {",
" opts = opts || {};",
" var depth = (opts.depth == null) ? 2 : opts.depth, allow = opts.edgeTypes || null, dir = opts.direction || 'both', maxNodes = opts.maxNodes || 600, noInf = opts.includeInferred === false;",
" var infStart = !!opts.inferredFromStartOnly, hubs = opts.hubTypes || null, noDesc = !!opts.containersFromStartOnly;",
" var seen = {}, order = [], queue = [], edges = [], edgeSeen = {}, truncated = false, i, cur, list, e, nb, key;",
" if (!idx.nodes[startId]) return { nodes: [], edges: [], truncated: false, depthOf: {} };",
" seen[startId] = 0; order.push(startId); queue.push(startId);",
" while (queue.length) {",
" cur = queue.shift();",
" if (seen[cur] >= depth) continue;",
" if (hubs && seen[cur] > 0 && idx.nodes[cur] && has(hubs, idx.nodes[cur].type)) continue; // ハブは起点でない限り広げない",
" list = [];",
" if (dir !== 'in') for (i = 0; i < (idx.out[cur] || []).length; i++) list.push({ e: idx.out[cur][i], nb: idx.out[cur][i].to });",
" if (dir !== 'out') for (i = 0; i < (idx.inn[cur] || []).length; i++) list.push({ e: idx.inn[cur][i], nb: idx.inn[cur][i].from });",
" for (i = 0; i < list.length; i++) {",
" e = list[i].e; nb = list[i].nb;",
" if (allow && !allow[e.type]) continue;",
" if (noInf && e.inferred) continue;",
" if (infStart && e.inferred && seen[cur] > 0) continue; // 導出した関係は起点からの 1 本目だけ",
" if (noDesc && seen[cur] > 0 && has(CONTAIN_ALL, e.type) && e.from === cur) continue; // 入れ物から別の中身へは起点のときだけ下りる (兄弟の属性・列・項目を出さない)",
" if (!has(seen, nb)) {",
" if (order.length >= maxNodes) { truncated = true; continue; }",
" seen[nb] = seen[cur] + 1; order.push(nb); queue.push(nb);",
" }",
" key = edgeKey(e);",
" if (!edgeSeen[key]) { edgeSeen[key] = 1; edges.push(e); }",
" }",
" }",
" // 取り込んだノードの間のエッジも足す (深さの縁どうし)",
" for (i = 0; i < order.length; i++) {",
" list = idx.out[order[i]] || [];",
" for (var j = 0; j < list.length; j++) {",
" e = list[j]; key = edgeKey(e);",
" if (has(seen, e.to) && !edgeSeen[key] && (!allow || allow[e.type]) && !(noInf && e.inferred)) { edgeSeen[key] = 1; edges.push(e); }",
" }",
" }",
" sortEdges(edges);",
" return { nodes: order, edges: edges, truncated: truncated, depthOf: seen };",
" };",
"",
" // ---- 種類の非表示と経由 (2026-10-09 案 B): hidden = { Item: true, … } の種類のノードを表示から除き、 除いたノードだけを通る「向きの揃った」経路で",
" // つながる表示ノード同士を 1 本の経由エッジ (type 'via'、 via: [除いたノード…]、 viaTypes: [通った関係…]) で結ぶ。 keep (起点・選択中) は残す。",
" // a → h → b のような一方向の経路だけ (a → h ← b の兄弟は結ばない = 2 つのブロックが同じ画面項目を持つのはブロック同士の関係ではない)。",
" // 表示ノード間に直接の関係が既にある組には足さない。 経路は 6 段まで、 経由エッジは maxVia 本まで。",
" // 戻り値は近傍と同じ形 + hidden (除いたノード数) + viaCount (経由エッジ数)。 隠す種類が無ければ入力をそのまま返す。",
" // ---- 内包の補完 (案 C、 2026-10-13): ブロックや画面項目が近傍に入ったら、 その入れ物 (機能 / ブロック) も深さを消費せずに足す (部分が出たら全体も出す)。 隠した種類の入れ物は足さない ----",
" CWG.completeContainers = function (sub, idx, opts) {",
" opts = opts || {};",
" var hidden = opts.hidden || {}, present = {}, ek = {}, nodes = sub.nodes.slice(), edges = sub.edges.slice(), depthOf = {}, i, k, id, e, par, added = 0, addedEdges = 0;",
" for (i = 0; i < nodes.length; i++) { present[nodes[i]] = 1; depthOf[nodes[i]] = (sub.depthOf || {})[nodes[i]] || 0; }",
" for (i = 0; i < edges.length; i++) ek[edgeKey(edges[i])] = 1;",
" for (i = 0; i < nodes.length; i++) { // nodes は途中で伸びる (足した入れ物の入れ物も見る)",
" id = nodes[i]; var inn = idx.inn[id] || [];",
" for (k = 0; k < inn.length; k++) {",
" e = inn[k]; if (!has(CONTAIN, e.type) || e.inferred) continue;",
" par = idx.nodes[e.from]; if (!par) continue;",
" if (hidden && hidden[par.type]) { // ★No.315: 隠した入れ物 (ブロック) は足さず、 その入れ物 (機能) を内包の経由 (via = hasBlock + hasItem) で結んで入れ子を保つ",
" var gIn = idx.inn[e.from] || [], g, ge, gp, vkey;",
" for (g = 0; g < gIn.length; g++) {",
" ge = gIn[g]; if (!has(CONTAIN, ge.type) || ge.inferred) continue;",
" gp = idx.nodes[ge.from]; if (!gp || (hidden && hidden[gp.type])) continue;",
" if (!present[ge.from]) { present[ge.from] = 1; nodes.push(ge.from); depthOf[ge.from] = depthOf[id]; added++; }",
" vkey = 'via\\t' + ge.from + '\\t' + id;",
" if (!ek[vkey]) { ek[vkey] = 1; edges.push({ from: ge.from, to: id, type: 'via', via: [e.from], viaTypes: [ge.type, e.type] }); addedEdges++; }",
" }",
" continue;",
" }",
" if (!present[e.from]) { present[e.from] = 1; nodes.push(e.from); depthOf[e.from] = depthOf[id]; added++; }",
" if (!ek[edgeKey(e)]) { ek[edgeKey(e)] = 1; edges.push(e); addedEdges++; }",
" }",
" }",
" if (!added && !addedEdges) return sub;",
" sortEdges(edges);",
" return { nodes: nodes, edges: edges, truncated: sub.truncated, depthOf: depthOf, containersAdded: added };",
" };",
" // 内包の線か: 内包の関係そのもの、 または隠した入れ物だけを通る経由 (★No.315: ブロックを隠したときの 機能 → 画面項目 = hasBlock + hasItem の経由)",
" function isContainEdge(e) {",
" if (has(CONTAIN, e.type)) return !e.inferred;",
" if (e.type !== 'via' || !e.viaTypes || !e.viaTypes.length) return false;",
" for (var i = 0; i < e.viaTypes.length; i++) if (!has(CONTAIN, e.viaTypes[i])) return false;",
" return true;",
" }",
" CWG.isContainEdge = isContainEdge;",
" // 入れ物の対応: 子の id → 入れ物の id (表示中の内包の線から。 畳み込みの束 (hasItem の束) も子になる。 隠した入れ物を通る経由も内包)",
" CWG.containerOf = function (sub, idx) {",
" var parent = {}, i, e;",
" for (i = 0; i < sub.edges.length; i++) {",
" e = sub.edges[i];",
" if (!isContainEdge(e) || e.from === e.to || has(parent, e.to)) continue;",
" if (!nodeOf(sub, idx, e.from) || !nodeOf(sub, idx, e.to)) continue;",
" parent[e.to] = e.from;",
" }",
" return parent;",
" };",
"",
" CWG.collapseTypes = function (sub, idx, hidden, opts) {",
" opts = opts || {};",
" var keep = opts.keep || {}, maxVia = opts.maxVia || 2000, maxHop = opts.maxHop || 6;",
" var isHidden = {}, hiddenCount = 0, i, j, e, id, n;",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; n = nodeOf(sub, idx, id);",
" if (n && hidden && hidden[n.type] && !has(keep, id)) { isHidden[id] = 1; hiddenCount++; }",
" }",
" if (!hiddenCount) return sub;",
" var direct = {}, out = {}, nodes = [], edges = [];",
" for (i = 0; i < sub.edges.length; i++) {",
" e = sub.edges[i];",
" if (!out[e.from]) out[e.from] = [];",
" out[e.from].push(e);",
" if (!isHidden[e.from] && !isHidden[e.to]) { direct[e.from + '\\t' + e.to] = 1; edges.push(e); }",
" }",
" for (i = 0; i < sub.nodes.length; i++) if (!isHidden[sub.nodes[i]]) nodes.push(sub.nodes[i]);",
" var viaEdges = [], viaSeen = {}, viaCount = 0, a, stack, visited, cur, lst, to, l0;",
" for (i = 0; i < nodes.length && viaCount < maxVia; i++) {",
" a = nodes[i]; stack = []; visited = {}; l0 = out[a] || [];",
" for (j = 0; j < l0.length; j++) if (isHidden[l0[j].to]) stack.push({ id: l0[j].to, via: [l0[j].to], types: [l0[j].type] });",
" while (stack.length && viaCount < maxVia) {",
" cur = stack.pop();",
" if (visited[cur.id]) continue;",
" visited[cur.id] = 1;",
" lst = out[cur.id] || [];",
" for (j = 0; j < lst.length; j++) {",
" to = lst[j].to;",
" if (isHidden[to]) { if (!visited[to] && cur.via.length < maxHop) stack.push({ id: to, via: cur.via.concat([to]), types: cur.types.concat([lst[j].type]) }); continue; }",
" if (to === a || direct[a + '\\t' + to] || viaSeen[a + '\\t' + to]) continue;",
" viaSeen[a + '\\t' + to] = 1; viaCount++;",
" viaEdges.push({ from: a, to: to, type: 'via', via: cur.via, viaTypes: cur.types.concat([lst[j].type]) });",
" }",
" }",
" }",
" for (i = 0; i < viaEdges.length; i++) edges.push(viaEdges[i]);",
" sortEdges(edges);",
" var depthOf = {};",
" for (i = 0; i < nodes.length; i++) depthOf[nodes[i]] = (sub.depthOf || {})[nodes[i]] || 0;",
" return { nodes: nodes, edges: edges, truncated: sub.truncated, depthOf: depthOf, virtual: sub.virtual, hidden: hiddenCount, viaCount: viaCount };",
" };",
"",
" // ---- 末端の畳み込み: 同じ中心 (hub) に同じ関係 (種類・向き・導出かどうか) で付く同じ種類の末端 (近傍の中で次数 1) が minSize 個以上なら 1 つの箱にまとめる ----",
" // opts = { minSize: 6, keep: { id: 1 } (起点・選択中 = まとめない), expanded: { bundleId: 1 } (押して展開した束), typeLabel: fn(type) → 表示名, fmt: '{0} ×{1}' }",
" // 戻り値は近傍と同じ形 + virtual (束の仮想ノード: type = 末端の種類、 bundle: true、 count、 members、 hub)。 束が無ければ入力をそのまま返す。",
" CWG.bundleLeaves = function (sub, idx, opts) {",
" opts = opts || {};",
" var minSize = opts.minSize || 6, keep = opts.keep || {}, expanded = opts.expanded || {}, typeLabel = opts.typeLabel || function (t) { return t; }, fmt = opts.fmt || '{0} ×{1}';",
" var deg = {}, i, e, id, k;",
" for (i = 0; i < sub.edges.length; i++) { e = sub.edges[i]; deg[e.from] = (deg[e.from] || 0) + 1; deg[e.to] = (deg[e.to] || 0) + 1; }",
" var groups = {}, order = [];",
" for (i = 0; i < sub.edges.length; i++) {",
" e = sub.edges[i];",
" var leaf = null, hub = null, dir = '';",
" if ((deg[e.to] || 0) === 1 && !has(keep, e.to) && (deg[e.from] || 0) > 1) { leaf = e.to; hub = e.from; dir = 'out'; }",
" else if ((deg[e.from] || 0) === 1 && !has(keep, e.from) && (deg[e.to] || 0) > 1) { leaf = e.from; hub = e.to; dir = 'in'; }",
" if (!leaf) continue;",
" var ln = idx.nodes[leaf]; if (!ln) continue;",
" var contain = isContainEdge(e); // ★No.315: 隠したブロックを通る内包の経由 (via) は、 他の経由と混ぜず内包として束ねる (束のエッジにも viaTypes を写す)",
" k = hub + '|' + dir + '|' + e.type + '|' + (e.inferred ? 'i' : 'a') + '|' + ln.type + (e.type === 'via' ? (contain ? '|c' : '|v') : '');",
" if (!has(groups, k)) { groups[k] = { hub: hub, dir: dir, type: e.type, inferred: !!e.inferred, nodeType: ln.type, members: [], edges: [], viaTypes: (e.type === 'via' && e.viaTypes) ? e.viaTypes.slice() : null, via: (e.type === 'via' && e.via) ? e.via.slice() : null }; order.push(k); }",
" groups[k].members.push(leaf); groups[k].edges.push(e);",
" }",
" var removeNode = {}, removeEdge = {}, virtual = {}, addNodes = [], addEdges = [], g, bundled = 0;",
" for (k = 0; k < order.length; k++) {",
" g = groups[order[k]];",
" var bid = 'bundle:' + order[k];",
" if (g.members.length < minSize || has(expanded, bid)) continue;",
" g.members.sort();",
" for (i = 0; i < g.members.length; i++) removeNode[g.members[i]] = 1;",
" for (i = 0; i < g.edges.length; i++) removeEdge[edgeKey(g.edges[i])] = 1;",
" virtual[bid] = { id: bid, type: g.nodeType, label: String(fmt).replace('{0}', typeLabel(g.nodeType)).replace('{1}', String(g.members.length)),",
" bundle: true, count: g.members.length, members: g.members, hub: g.hub, edgeType: g.type, props: {} };",
" addNodes.push(bid); bundled += g.members.length;",
" var be = g.dir === 'out' ? { from: g.hub, to: bid, type: g.type, inferred: g.inferred, bundle: true } : { from: bid, to: g.hub, type: g.type, inferred: g.inferred, bundle: true };",
" if (g.viaTypes) { be.viaTypes = g.viaTypes; be.via = g.via; }",
" addEdges.push(be);",
" }",
" if (!addNodes.length) return sub;",
" var nodes = [], edges = [], depthOf = {};",
" for (i = 0; i < sub.nodes.length; i++) { id = sub.nodes[i]; if (!removeNode[id]) { nodes.push(id); depthOf[id] = (sub.depthOf || {})[id] || 0; } }",
" for (i = 0; i < addNodes.length; i++) { nodes.push(addNodes[i]); depthOf[addNodes[i]] = ((sub.depthOf || {})[virtual[addNodes[i]].hub] || 0) + 1; }",
" for (i = 0; i < sub.edges.length; i++) if (!removeEdge[edgeKey(sub.edges[i])]) edges.push(sub.edges[i]);",
" for (i = 0; i < addEdges.length; i++) edges.push(addEdges[i]);",
" sortEdges(edges);",
" return { nodes: nodes, edges: edges, truncated: sub.truncated, depthOf: depthOf, virtual: virtual, bundled: bundled, bundleCount: addNodes.length };",
" };",
"",
" // ---- 箱の大きさ: sizeBy = 'none' (一律) | 'local' (表示中の近傍の関係の数) | 'global' (設計書全体の関係の数、 導出を除く)。 次数の対数で高さ 24〜38px、 文字 10.5〜14.6px ----",
" // 束 (bundle) はまとめた数を次数とみなす。 戻り値 = { id: { w, h, fs, deg } }",
" CWG.nodeSizes = function (sub, idx, opts) {",
" opts = opts || {};",
" var mode = opts.sizeBy || 'none', deg = {}, maxDeg = 0, i, id, n, e, sizes = {};",
" if (mode === 'local') {",
" for (i = 0; i < sub.edges.length; i++) { e = sub.edges[i]; deg[e.from] = (deg[e.from] || 0) + 1; deg[e.to] = (deg[e.to] || 0) + 1; }",
" } else if (mode === 'global') {",
" for (i = 0; i < sub.nodes.length; i++) deg[sub.nodes[i]] = idx.deg[sub.nodes[i]] || 0;",
" maxDeg = idx.maxDeg || 0;",
" }",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; n = nodeOf(sub, idx, id);",
" if (n && n.bundle && mode !== 'none') deg[id] = Math.max(deg[id] || 0, n.count || 0);",
" if ((deg[id] || 0) > maxDeg) maxDeg = deg[id];",
" }",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; n = nodeOf(sub, idx, id); if (!n) continue;",
" var sc = (mode === 'none' || maxDeg <= 0) ? 1 : 1 + 0.6 * Math.log(1 + (deg[id] || 0)) / Math.log(1 + maxDeg);",
" var fs = Math.round(10.5 * (1 + (sc - 1) * 0.65) * 10) / 10, h = Math.round(NODE_H * sc);",
" var w = Math.min(n.type === 'Function' ? 380 : 300, Math.max(70, textW(displayLabel(n)) * (fs / 10.5) + 18)); // 機能は「機能名 (機能ID)」で長いので上限を広く (案 C の枠の見出し)",
" sizes[id] = { w: w, h: h, fs: fs, deg: deg[id] || 0 };",
" }",
" return sizes;",
" };",
"",
" // ---- 系譜 (レーン配置): レーン = 種類で決め、 レーン内の並びは隣のレーンの重心で整える (交差を減らす) ----",
" // opts = { spacing: 'auto' | 'compact' | 'normal' | 'wide' | 'widest', sizeBy, sizes }",
" CWG.layoutLayered = function (sub, idx, opts) {",
" opts = opts || {};",
" var sp = spacingOf(opts, sub.nodes.length), sizes = opts.sizes || CWG.nodeSizes(sub, idx, opts), laneGap = LANE_GAP * sp.lane, rowGap = ROW_GAP * sp.row;",
" var laneNodes = [], i, n, id, lane, pos = {}, laneW = [], parent = CWG.containerOf(sub, idx), children = {}, rootOf = {}, gsz = {};",
" for (lane = 0; lane < NL; lane++) { laneNodes.push([]); laneW.push(0); }",
" function laneOfId(x) { var nn = nodeOf(sub, idx, x); return nn ? (has(LANE_OF, nn.type) ? LANE_OF[nn.type] : NL - 1) : -1; }",
" // 入れ子 (案 C、 2026-10-13): 入れ物が同じレーンにあるノードは、 その入れ物の枠の中に子として置く (機能 ⊃ ブロック ⊃ 画面項目)。 レーンの行は根 (入れ物の無いノード) だけ",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; if (!nodeOf(sub, idx, id)) continue;",
" var pa = has(parent, id) ? parent[id] : null;",
" if (pa != null && pa !== id && laneOfId(pa) === laneOfId(id)) { if (!children[pa]) children[pa] = []; children[pa].push(id); } else parent[id] = null;",
" }",
" function childOrder(a, b) { // 子の並び: 種類の副順位 → ブロック番号 (props.no) → id",
" var na = nodeOf(sub, idx, a), nb = nodeOf(sub, idx, b), ra = SUB_RANK[na.type] || 0, rb = SUB_RANK[nb.type] || 0;",
" if (ra !== rb) return ra - rb;",
" var oa = (na.props && na.props.no != null) ? Number(na.props.no) : null, ob = (nb.props && nb.props.no != null) ? Number(nb.props.no) : null;",
" if (oa != null && ob != null && oa !== ob) return oa - ob;",
" return a < b ? -1 : (a > b ? 1 : 0);",
" }",
" function rootIdOf(x) { var guard = 0; while (parent[x] != null && guard++ < 50) x = parent[x]; return x; }",
" function groupSize(x) { // 枠の大きさ (子を含む): 幅 = 自分と子の最大 + 字下げ、 高さ = 見出し + 子の合計 + 余白",
" if (gsz[x]) return gsz[x];",
" var own = sizes[x], w = own.w, h = own.h, cs = children[x] || [], c;",
" if (cs.length) {",
" cs.sort(childOrder);",
" var cw = 0, ch = 0;",
" for (c = 0; c < cs.length; c++) { var g = groupSize(cs[c]); if (g.w > cw) cw = g.w; ch += g.h + (c ? rowGap : 0); }",
" w = Math.max(w, NEST_INDENT + cw + NEST_PAD); h = own.h + NEST_PAD + ch + NEST_PAD;",
" }",
" gsz[x] = { w: w, h: h }; return gsz[x];",
" }",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; n = nodeOf(sub, idx, id); if (!n) continue; lane = laneOfId(id);",
" rootOf[id] = rootIdOf(id);",
" if (parent[id] != null) continue;",
" laneNodes[lane].push(id);",
" var gs = groupSize(id); if (gs.w > laneW[lane]) laneW[lane] = gs.w;",
" }",
" // 初期順: 起点の深さ → id",
" var depthOf = sub.depthOf || {};",
" for (lane = 0; lane < NL; lane++) laneNodes[lane].sort(function (a, b) { var da = depthOf[a] || 0, db = depthOf[b] || 0; return da !== db ? da - db : (a < b ? -1 : 1); });",
" // 重心法 (左→右、 右→左 を 2 往復)。 枠の中の子の関係は根の重心に数える",
" var adj = {}, e;",
" for (i = 0; i < sub.edges.length; i++) {",
" e = sub.edges[i]; var ra = rootOf[e.from] || e.from, rb = rootOf[e.to] || e.to; if (ra === rb) continue;",
" if (!adj[ra]) adj[ra] = []; if (!adj[rb]) adj[rb] = []; adj[ra].push(rb); adj[rb].push(ra);",
" }",
" var rowOf = {};",
" function setRows(lane) { for (var r = 0; r < laneNodes[lane].length; r++) rowOf[laneNodes[lane][r]] = r; }",
" for (lane = 0; lane < NL; lane++) setRows(lane);",
" function sweep(lane, refLane) {",
" var bc = {}, k;",
" for (k = 0; k < laneNodes[lane].length; k++) {",
" id = laneNodes[lane][k]; var sum = 0, cnt = 0, nbs = adj[id] || [];",
" for (var m = 0; m < nbs.length; m++) { if (laneOfId(nbs[m]) === refLane && has(rowOf, nbs[m])) { sum += rowOf[nbs[m]]; cnt++; } }",
" bc[id] = cnt ? sum / cnt : rowOf[id];",
" }",
" laneNodes[lane].sort(function (a, b) { // 同じレーンでは種類の副順位 (テーブル → 列 など) を先に、 その中で重心 (隣のレーンとの交差を減らす)",
" var ra = SUB_RANK[nodeOf(sub, idx, a).type] || 0, rb = SUB_RANK[nodeOf(sub, idx, b).type] || 0;",
" if (ra !== rb) return ra - rb;",
" return bc[a] !== bc[b] ? bc[a] - bc[b] : (a < b ? -1 : 1);",
" });",
" setRows(lane);",
" }",
" for (var pass = 0; pass < 2; pass++) {",
" for (lane = 1; lane < NL; lane++) if (laneNodes[lane].length) sweep(lane, lane - 1);",
" for (lane = NL - 2; lane >= 0; lane--) if (laneNodes[lane].length) sweep(lane, lane + 1);",
" }",
" // 座標: 空のレーンは詰める。 行の高さは箱 (入れ物なら枠) ごと。 上端はレーン名 + 種類の小見出しのぶん空ける (LANE_TOP)",
" var x = PAD, laneX = {}, maxTotal = 0, usedLanes = [], laneTotal = [], r;",
" for (lane = 0; lane < NL; lane++) laneTotal.push(0);",
" for (lane = 0; lane < NL; lane++) {",
" if (!laneNodes[lane].length) continue;",
" laneX[lane] = x; usedLanes.push(lane); x += laneW[lane] + laneGap;",
" for (r = 0; r < laneNodes[lane].length; r++) laneTotal[lane] += groupSize(laneNodes[lane][r]).h + (r ? rowGap : 0);",
" if (laneTotal[lane] > maxTotal) maxTotal = laneTotal[lane];",
" }",
" var H = LANE_TOP + PAD + maxTotal, W = x - laneGap + PAD;",
" function place(x0, y0, w0, lane0, nid, level) { // 枠の中に子を字下げして並べる。 子の幅は枠いっぱい (右端を揃える)",
" var own = sizes[nid], g = groupSize(nid), cs = children[nid] || [], c, gw = Math.max(w0, g.w);",
" pos[nid] = { x: x0, y: y0, w: gw, h: own.h, fs: own.fs, lane: lane0, level: level, frame: cs.length ? { x: x0, y: y0, w: gw, h: g.h } : null };",
" var yy = y0 + own.h + NEST_PAD;",
" for (c = 0; c < cs.length; c++) { place(x0 + NEST_INDENT, yy, gw - NEST_INDENT - NEST_PAD, lane0, cs[c], level + 1); yy += groupSize(cs[c]).h + rowGap; }",
" }",
" for (var li = 0; li < usedLanes.length; li++) {",
" lane = usedLanes[li];",
" var y = LANE_TOP + (H - LANE_TOP - PAD - laneTotal[lane]) / 2;",
" for (r = 0; r < laneNodes[lane].length; r++) {",
" id = laneNodes[lane][r];",
" place(laneX[lane], y, sizes[id].w, lane, id, 0);",
" y += groupSize(id).h + rowGap;",
" }",
" }",
" return { pos: pos, width: Math.max(W, 300), height: Math.max(H, 120), lanes: usedLanes, laneX: laneX, laneW: laneW, mode: 'layered', spacing: sp, parent: parent };",
" };",
"",
" // ---- 関係図 (力学モデル): 決定的な初期配置 (id のハッシュ) からばねと反発で収束させる。 opts.spacing で基準距離・描画領域・余白を変える ----",
" CWG.layoutForce = function (sub, idx, opts) {",
" opts = opts || {};",
" var n = sub.nodes.length, sp = spacingOf(opts, n), sizes = opts.sizes || CWG.nodeSizes(sub, idx, opts);",
" var W = (opts.width || Math.max(700, Math.round(Math.sqrt(n) * 170))) * sp.k, H = (opts.height || Math.max(500, Math.round(Math.sqrt(n) * 125))) * sp.k;",
" var avgW = 0, wi; for (wi = 0; wi < n; wi++) avgW += sizes[sub.nodes[wi]].w; avgW = n ? avgW / n : 100;",
" var iters = opts.iterations || 260, pos = {}, i, j, id, k = Math.max(Math.sqrt((W * H) / Math.max(n, 1)), avgW * 0.85) * sp.k, t = Math.max(W, H) / 10;",
" function hash(s) { var h = 2166136261, q; for (q = 0; q < s.length; q++) { h ^= s.charCodeAt(q); h = (h * 16777619) >>> 0; } return h; }",
" var P = [];",
" for (i = 0; i < n; i++) {",
" id = sub.nodes[i]; var h1 = hash(id), ang = (h1 % 3600) / 3600 * Math.PI * 2, rad = 0.25 + ((h1 >>> 12) % 1000) / 1000 * 0.4;",
" P.push({ id: id, x: W / 2 + Math.cos(ang) * rad * W / 2, y: H / 2 + Math.sin(ang) * rad * H / 2, dx: 0, dy: 0 });",
" }",
" var at = {}; for (i = 0; i < n; i++) at[P[i].id] = i;",
" var E = [];",
" for (i = 0; i < sub.edges.length; i++) if (has(at, sub.edges[i].from) && has(at, sub.edges[i].to)) E.push([at[sub.edges[i].from], at[sub.edges[i].to]]);",
" for (var it = 0; it < iters; it++) {",
" for (i = 0; i < n; i++) { P[i].dx = 0; P[i].dy = 0; }",
" for (i = 0; i < n; i++) for (j = i + 1; j < n; j++) {",
" var ddx = P[i].x - P[j].x, ddy = P[i].y - P[j].y, d2 = ddx * ddx + ddy * ddy; if (d2 < 0.01) { ddx = 0.1 * ((i % 2) ? 1 : -1); ddy = 0.1; d2 = 0.02; }",
" var d = Math.sqrt(d2), f = (k * k) / d;",
" P[i].dx += ddx / d * f; P[i].dy += ddy / d * f; P[j].dx -= ddx / d * f; P[j].dy -= ddy / d * f;",
" }",
" for (i = 0; i < E.length; i++) {",
" var a = P[E[i][0]], b = P[E[i][1]], ex = a.x - b.x, ey = a.y - b.y, ed = Math.sqrt(ex * ex + ey * ey) || 0.1, ef = (ed * ed) / k;",
" a.dx -= ex / ed * ef; a.dy -= ey / ed * ef; b.dx += ex / ed * ef; b.dy += ey / ed * ef;",
" }",
" for (i = 0; i < n; i++) {",
" var dl = Math.sqrt(P[i].dx * P[i].dx + P[i].dy * P[i].dy) || 0.1, step = Math.min(dl, t);",
" P[i].x += P[i].dx / dl * step; P[i].y += P[i].dy / dl * step;",
" // 中心への弱い引力 (散らばり過ぎ防止)",
" P[i].x += (W / 2 - P[i].x) * 0.01; P[i].y += (H / 2 - P[i].y) * 0.01;",
" }",
" t = Math.max(t * 0.96, 1);",
" }",
" // 重なりをほどく (箱どうしが重なっていれば離す。 40 回まで。 余白はプリセットの gap)",
" var gap = sp.gap, ri, rj, rp;",
" for (rp = 0; rp < 40; rp++) {",
" var moved = false;",
" for (ri = 0; ri < n; ri++) for (rj = ri + 1; rj < n; rj++) {",
" var si = sizes[P[ri].id], sj = sizes[P[rj].id];",
" var ox = (si.w + sj.w) / 2 + gap - Math.abs(P[ri].x - P[rj].x), oy = (si.h + sj.h) / 2 + gap - Math.abs(P[ri].y - P[rj].y);",
" if (ox <= 0 || oy <= 0) continue;",
" moved = true;",
" if (ox < oy) { var sx = (P[ri].x < P[rj].x ? -1 : 1) * ox / 2; P[ri].x += sx; P[rj].x -= sx; }",
" else { var sy = (P[ri].y < P[rj].y ? -1 : 1) * oy / 2; P[ri].y += sy; P[rj].y -= sy; }",
" }",
" if (!moved) break;",
" }",
" var minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;",
" for (i = 0; i < n; i++) { var sz = sizes[P[i].id]; pos[P[i].id] = { x: P[i].x - sz.w / 2, y: P[i].y - sz.h / 2, w: sz.w, h: sz.h, fs: sz.fs, cx: P[i].x, cy: P[i].y };",
" if (P[i].x - sz.w / 2 < minX) minX = P[i].x - sz.w / 2; if (P[i].y - sz.h / 2 < minY) minY = P[i].y - sz.h / 2; if (P[i].x + sz.w / 2 > maxX) maxX = P[i].x + sz.w / 2; if (P[i].y + sz.h / 2 > maxY) maxY = P[i].y + sz.h / 2; }",
" if (n === 0) { minX = 0; minY = 0; maxX = 300; maxY = 120; }",
" for (i = 0; i < n; i++) { var p = pos[P[i].id]; p.x += PAD - minX; p.y += PAD - minY; p.cx += PAD - minX; p.cy += PAD - minY; }",
" return { pos: pos, width: Math.round(maxX - minX + PAD * 2), height: Math.round(maxY - minY + PAD * 2), mode: 'force', spacing: sp };",
" };",
"",
" // ---- 描画 (SVG 文字列)。 colorOf(node) で塗り分け、 L = 文言 ----",
" CWG.renderSvg = function (sub, lay, idx, opts) {",
" opts = opts || {};",
" var L = opts.L || {}, ont = opts.ontology || null, colorOf = opts.colorOf || function (n) { return TYPE_COLOR[n.type] || '#94a3b8'; };",
" var startId = opts.startId || null, selected = opts.selectedId || null, showEdgeLabels = !!opts.edgeLabels, lang = opts.lang || 'ja', hiddenTypes = opts.hiddenTypes || {};",
" var s = '', i, e, id, n, p;",
" function labelOf(x) { var nn = nodeOf(sub, idx, x); return nn ? displayLabel(nn) : x; }",
" s += '<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"cwg-svg\" data-mode=\"' + lay.mode + '\" viewBox=\"0 0 ' + lay.width + ' ' + lay.height + '\" width=\"' + lay.width + '\" height=\"' + lay.height + '\">';",
" s += '<defs><marker id=\"cwg-arrow\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0,0 L10,5 L0,10 z\" fill=\"#64748b\"/></marker></defs>';",
" s += '<rect x=\"0\" y=\"0\" width=\"' + lay.width + '\" height=\"' + lay.height + '\" fill=\"#ffffff\"/>';",
" if (lay.mode === 'layered') { // レーンの見出し + そのレーンに表示中の種類の名前 (小さく)。 ★2026-10-12 テスター要望「文脈はプロジェクトか」、 10-13 表示中の種類だけ",
" var present = {}, pi, pn;",
" for (pi = 0; pi < sub.nodes.length; pi++) { pn = nodeOf(sub, idx, sub.nodes[pi]); if (pn) present[pn.type] = 1; }",
" for (i = 0; i < lay.lanes.length; i++) {",
" var ln = lay.lanes[i], lx = lay.laneX[ln], lw = lay.laneW[ln];",
" var lts = laneTypes(ln), ltNames = [], q;",
" var hidNames = []; // 隠している種類 (凡例で外した種類) はそのレーンの小見出しに「X は非表示」と添える (2026-10-13 ユーザー承認: 隠れていることを図の中で分かるように)",
" for (q = 0; q < lts.length; q++) {",
" var tnm = (ont && ont.nodeTypes && ont.nodeTypes[lts[q]] && ont.nodeTypes[lts[q]].label && ont.nodeTypes[lts[q]].label[lang]) || lts[q];",
" if (present[lts[q]]) ltNames.push(tnm); else if (hiddenTypes[lts[q]] && idx.byType && idx.byType[lts[q]] && idx.byType[lts[q]].length) hidNames.push(tnm);",
" }",
" var hidNote = hidNames.length ? ' (' + String(L.hiddenNote || '{0} hidden').replace('{0}', hidNames.join(' / ')) + ')' : '';",
" s += '<rect x=\"' + (lx - 8) + '\" y=\"6\" width=\"' + (lw + 16) + '\" height=\"' + (lay.height - 12) + '\" fill=\"#f8fafc\" stroke=\"#e2e8f0\" rx=\"6\"/>';",
" s += '<text x=\"' + (lx + lw / 2) + '\" y=\"20\" font-size=\"11\" fill=\"#64748b\" text-anchor=\"middle\">' + esc((L.lanes && L.lanes[LANES[ln]]) || LANES[ln]) + '</text>';",
" s += '<text class=\"cwg-lane-types\" x=\"' + (lx + lw / 2) + '\" y=\"33\" font-size=\"8.5\" fill=\"#94a3b8\" text-anchor=\"middle\">' + esc(ltNames.join(' / ') + hidNote) + '</text>';",
" }",
" }",
" if (lay.mode === 'layered') { // 入れ子の枠 (案 C): 外側から順に、 箱の下に描く (クリックは通さない = 中の箱が押せる)",
" var fr = [], fi, fp, fn;",
" for (fi = 0; fi < sub.nodes.length; fi++) { fp = lay.pos[sub.nodes[fi]]; if (fp && fp.frame) fr.push(sub.nodes[fi]); }",
" fr.sort(function (a, b) { return (lay.pos[a].level || 0) - (lay.pos[b].level || 0); });",
" for (fi = 0; fi < fr.length; fi++) {",
" fn = nodeOf(sub, idx, fr[fi]); fp = lay.pos[fr[fi]]; var fc = colorOf(fn);",
" s += '<rect class=\"cwg-frame\" data-for=\"' + esc(fr[fi]) + '\" x=\"' + Math.round(fp.frame.x - 2) + '\" y=\"' + Math.round(fp.frame.y - 2) + '\" width=\"' + Math.round(fp.frame.w + 4) + '\" height=\"' + Math.round(fp.frame.h + 4) + '\" rx=\"7\" fill=\"' + fc + '\" fill-opacity=\"0.08\" stroke=\"' + fc + '\" stroke-opacity=\"0.45\" pointer-events=\"none\"/>';",
" }",
" }",
" function edgeLabel(t) { if (t === 'via') return L.via || 'via'; return (ont && ont.edgeTypes && ont.edgeTypes[t] && ont.edgeTypes[t].label && ont.edgeTypes[t].label[lang]) || t; }",
" function viaPath(e) { var s = [], k; for (k = 0; k < (e.via || []).length; k++) s.push(labelOf(e.via[k])); return s.join(' → '); } // 経由した (隠した) ノードの名前",
" // エッジ",
" for (i = 0; i < sub.edges.length; i++) {",
" e = sub.edges[i]; var a = lay.pos[e.from], b = lay.pos[e.to]; if (!a || !b) continue;",
" if (lay.mode === 'layered' && lay.parent && lay.parent[e.to] === e.from && isContainEdge(e)) continue; // 内包は入れ子で表す (線は描かない。 隠した入れ物を通る経由も)",
" var x1, y1, x2, y2, d;",
" if (lay.mode === 'layered') {",
" if (a.lane < b.lane) { x1 = a.x + a.w; y1 = a.y + a.h / 2; x2 = b.x; y2 = b.y + b.h / 2; d = 'M' + x1 + ',' + y1 + ' C' + (x1 + (x2 - x1) / 2) + ',' + y1 + ' ' + (x1 + (x2 - x1) / 2) + ',' + y2 + ' ' + x2 + ',' + y2; }",
" else if (a.lane > b.lane) { x1 = a.x; y1 = a.y + a.h / 2; x2 = b.x + b.w; y2 = b.y + b.h / 2; d = 'M' + x1 + ',' + y1 + ' C' + (x1 - (x1 - x2) / 2) + ',' + y1 + ' ' + (x1 - (x1 - x2) / 2) + ',' + y2 + ' ' + x2 + ',' + y2; }",
" else { x1 = a.x + a.w; y1 = a.y + a.h / 2; x2 = b.x + b.w; y2 = b.y + b.h / 2; var bulge = 30 + Math.abs(y2 - y1) / 6; d = 'M' + x1 + ',' + y1 + ' C' + (x1 + bulge) + ',' + y1 + ' ' + (x2 + bulge) + ',' + y2 + ' ' + x2 + ',' + y2; } // 同じレーン: 右側に弧",
" } else {",
" x1 = a.cx; y1 = a.cy; x2 = b.cx; y2 = b.cy;",
" var vx = x2 - x1, vy = y2 - y1, vl = Math.sqrt(vx * vx + vy * vy) || 1, cut = Math.min(b.w / 2 + 6, vl / 2); // 終点は箱の手前で止める",
" x2 = x2 - vx / vl * cut; y2 = y2 - vy / vl * cut;",
" d = 'M' + Math.round(x1) + ',' + Math.round(y1) + ' L' + Math.round(x2) + ',' + Math.round(y2);",
" }",
" var hi = (selected && (e.from === selected || e.to === selected)), stroke = hi ? '#f59e0b' : '#94a3b8';",
" s += '<path class=\"cwg-edge\" data-type=\"' + esc(e.type) + '\" data-from=\"' + esc(e.from) + '\" data-to=\"' + esc(e.to) + '\"' + (e.inferred ? ' data-inferred=\"1\" stroke-dasharray=\"5,3\"' : '') + (e.bundle ? ' data-bundle=\"1\"' : '') + (e.type === 'via' ? ' data-via=\"1\" stroke-dasharray=\"2,4\"' : '') + ' d=\"' + d + '\" fill=\"none\" stroke=\"' + stroke + '\" stroke-width=\"' + (hi ? 2 : (e.bundle ? 2 : 1.2)) + '\" marker-end=\"url(#cwg-arrow)\"><title>' + esc(edgeLabel(e.type) + ': ' + labelOf(e.from) + ' → ' + labelOf(e.to) + (e.inferred ? ' [' + (L.inferred || 'inferred') + ': ' + e.rule + ']' : '') + (e.type === 'via' ? ' [' + (L.via || 'via') + ': ' + viaPath(e) + ']' : '')) + '</title></path>';",
" if (showEdgeLabels) s += '<text x=\"' + Math.round((x1 + x2) / 2) + '\" y=\"' + Math.round((y1 + y2) / 2 - 3) + '\" font-size=\"9\" fill=\"#64748b\" text-anchor=\"middle\">' + esc(edgeLabel(e.type)) + '</text>';",
" }",
" // ノード (箱の高さと文字の大きさは配置が決めた pos.h / pos.fs。 束は破線の枠)",
" for (i = 0; i < sub.nodes.length; i++) {",
" id = sub.nodes[i]; n = nodeOf(sub, idx, id); p = lay.pos[id]; if (!n || !p) continue;",
" var col = colorOf(n), isStart = id === startId, isSel = id === selected, light = (n.type === 'Item' || n.type === 'Column' || n.type === 'EdmAttribute' || n.type === 'PhysAttr'), fs = p.fs || 10.5;",
" s += '<g class=\"cwg-node\" data-id=\"' + esc(id) + '\" data-type=\"' + esc(n.type) + '\"' + (n.bundle ? ' data-bundle=\"1\" data-count=\"' + n.count + '\"' : '') + ' style=\"cursor:pointer\">';",
" s += '<rect x=\"' + Math.round(p.x) + '\" y=\"' + Math.round(p.y) + '\" width=\"' + Math.round(p.w) + '\" height=\"' + p.h + '\" rx=\"5\" fill=\"' + col + '\" fill-opacity=\"' + (light ? '0.55' : '0.9') + '\" stroke=\"' + (isStart ? '#dc2626' : (isSel ? '#f59e0b' : '#334155')) + '\" stroke-width=\"' + (isStart || isSel ? 2.5 : (n.bundle ? 1.5 : 1)) + '\"' + (n.bundle ? ' stroke-dasharray=\"4,3\"' : '') + '/>';",
" var lbl = displayLabel(n) || String(id); if (textW(lbl) * (fs / 10.5) > p.w - 10) { while (lbl.length > 1 && (textW(lbl) + 10) * (fs / 10.5) > p.w - 10) lbl = lbl.substring(0, lbl.length - 1); lbl += '…'; }",
" s += '<text x=\"' + Math.round(p.x + p.w / 2) + '\" y=\"' + Math.round(p.y + p.h / 2 + fs * 0.38) + '\" font-size=\"' + fs + '\" font-family=\"sans-serif\" text-anchor=\"middle\" fill=\"' + (light ? '#1f2937' : '#ffffff') + '\">' + esc(lbl) + '</text>';",
" var tn = (ont && ont.nodeTypes && ont.nodeTypes[n.type] && ont.nodeTypes[n.type].label && ont.nodeTypes[n.type].label[lang]) || n.type;",
" s += '<title>' + esc(displayLabel(n) + ' [' + tn + ']' + (n.bundle ? ' — ' + (L.expand || 'click to expand') : '')) + '</title></g>';",
" }",
" s += '</svg>';",
" return s;",
" };",
"",
"",
" // ---- 起点の検索 (★No.301 / 302、 2026-10-09) ----",
" // 表示名のほかに props の名前 (テーブルの論理名 logicalName / 物理名 physicalName / 項目の表示名 dispName / ブロックの title / name) と id も対象にする。",
" // 並び = 表示名に当たったもの → 他の名前に当たったもの → id だけに当たったもの の組。 組の中では種類の順 (機能 → テーブル → データドメイン → EDM / エンティティ →",
" // 業務分類 / プロジェクト / 部門 → ブロック → EDM 属性 → 物理属性 → 列 → 項目) → 前方一致を先に → 表示名の順。 上限を超えた分は more に数える (id 順に打ち切らない)",
" var SEARCH_PROPS = ['logicalName', 'physicalName', 'name', 'dispName', 'title'];",
" var SEARCH_RANK = { Function: 0, Table: 1, DataDomain: 2, Edm: 3, EdmEntity: 3, Category: 4, Project: 4, Dept: 4, Block: 5, EdmAttribute: 6, PhysAttr: 7, Column: 8, Item: 9, SubtypeNode: 10 };",
" function normText(s) { s = String(s == null ? '' : s); try { s = s.normalize('NFKC'); } catch (e) {} return s.toLowerCase(); }",
" CWG.normText = normText;",
" CWG.searchIndex = function (idx) {",
" var out = {}, i, id, n, j, p, v, seen, alts, lab, nv;",
" for (i = 0; i < idx.order.length; i++) {",
" id = idx.order[i]; n = idx.nodes[id]; alts = []; seen = {};",
" lab = normText(n.label); seen[lab] = 1;",
" for (j = 0; j < SEARCH_PROPS.length; j++) {",
" p = SEARCH_PROPS[j]; v = n.props ? n.props[p] : null;",
" if (!v || typeof v !== 'string') continue;",
" nv = normText(v); if (has(seen, nv)) continue; seen[nv] = 1;",
" alts.push({ key: p, text: v, norm: nv });",
" }",
" out[id] = { label: lab, alts: alts, id: normText(id) };",
" }",
" return out;",
" };",
" CWG.searchNodes = function (idx, sidx, query, opts) {",
" opts = opts || {};",
" var limit = opts.limit || 40, v = normText(query), hits = [], i, id, s, score, via, k, pos, tr;",
" if (!v) return { hits: [], more: 0 };",
" for (i = 0; i < idx.order.length; i++) {",
" id = idx.order[i]; s = sidx[id]; if (!s) continue; score = -1; via = null;",
" pos = s.label.indexOf(v); // 組 0 = 表示名 / 1 = 他の名前 / 2 = id。 組の中では種類の順 → 前方一致を先に → 表示名の順",
" if (pos >= 0) score = 0;",
" else {",
" for (k = 0; k < s.alts.length; k++) {",
" var ap = s.alts[k].norm.indexOf(v);",
" if (ap >= 0 && (score < 0 || ap < pos)) { score = 1; via = s.alts[k]; pos = ap; if (ap === 0) break; }",
" }",
" if (score < 0 && s.id.indexOf(v) >= 0) { score = 2; pos = s.id.indexOf(v); }",
" }",
" if (score < 0) continue;",
" tr = has(SEARCH_RANK, idx.nodes[id].type) ? SEARCH_RANK[idx.nodes[id].type] : 50;",
" hits.push({ id: id, score: score * 100 + tr, pos: pos, via: via ? { key: via.key, text: via.text } : null, label: s.label });",
" }",
" hits.sort(function (a, b) { return (a.score - b.score) || ((a.pos === 0 ? 0 : 1) - (b.pos === 0 ? 0 : 1)) || (a.label < b.label ? -1 : (a.label > b.label ? 1 : 0)) || (a.id < b.id ? -1 : (a.id > b.id ? 1 : 0)); });",
" return { hits: hits.slice(0, limit), more: Math.max(0, hits.length - limit) };",
" };",
"",
" // ---- 色分けのキー (★No.303、 2026-10-09) ----",
" // 業務分類 (機能の props.category[0] = 大分類) / プロジェクト / 責任部門 (データドメインの props) を持つノードを色の出所にして、 表示中の関係をたどって周りにも色を伝える",
" // (COLOR_FLOWS = キーが流れる関係と向き。 out = from → to、 in = to → from)。 伝わった先で違うキーが混ざれば mixed。 自分のキーを持つノードには伝えない。",
" // 戻り値 { keyOf: {id: key}, mixed: {id: 1}, keys: [key…] (表示名の順)、 labelOf: {key: 表示名} } — 凡例と塗り分けの両方が使う (純関数、 tests/test_graph_explorer.py)",
" var COLOR_FLOWS = {",
" category: [['hasBlock', 'out'], ['hasItem', 'out'], ['reads', 'out'], ['writes', 'out'], ['updates', 'out'], ['hasColumn', 'out'], ['storesIn', 'out'], ['matchesDomain', 'out'], ['itemMatches', 'out'],",
" ['usesDomain', 'out'], ['handlesEntity', 'out'], ['mapsTo', 'in'], ['hasPhysAttr', 'out'], ['declares', 'out'], ['hasAttribute', 'in'], ['hasEntity', 'in'], ['belongsTo', 'out'], ['childOf', 'out']],",
" project: [['hasPhysAttr', 'out'], ['declares', 'out'], ['matchesDomain', 'in'], ['itemMatches', 'in'], ['matchesColumn', 'out'], ['storedIn', 'out'], ['appearsIn', 'out'], ['usesDomain', 'in'],",
" ['hasAttribute', 'in'], ['hasEntity', 'in'], ['hasColumn', 'in'], ['hasItem', 'in'], ['hasBlock', 'in'], ['inProject', 'out']],",
" dept: [['hasPhysAttr', 'out'], ['declares', 'out'], ['matchesDomain', 'in'], ['itemMatches', 'in'], ['matchesColumn', 'out'], ['storedIn', 'out'], ['appearsIn', 'out'], ['usesDomain', 'in'],",
" ['hasAttribute', 'in'], ['hasEntity', 'in'], ['hasColumn', 'in'], ['hasItem', 'in'], ['hasBlock', 'in'], ['ownedBy', 'out']]",
" };",
" function ownColorKey(n, by) {",
" if (!n) return null;",
" var p = n.props || {};",
" if (by === 'category') {",
" if (n.type === 'Function') return (p.category && p.category[0]) ? String(p.category[0]) : null;",
" if (n.type === 'Category') return (p.level === 'L' && p.code) ? String(p.code) : null;",
" return null;",
" }",
" if (by === 'project') {",
" if (n.type === 'DataDomain') return (p.project && p.project.length) ? p.project.slice().sort().join(';') : null;",
" if (n.type === 'Project') return (String(n.id).indexOf('project:') === 0) ? String(n.id).substring(8) : null;",
" return null;",
" }",
" if (by === 'dept') {",
" if (n.type === 'DataDomain') return p.dept ? String(p.dept) : null;",
" if (n.type === 'Dept') return n.label ? String(n.label) : null;",
" return null;",
" }",
" return null;",
" }",
" function ownColorLabel(n, by, key) { // 凡例の表示名: 業務分類は名前 (機能の categoryNames[0] / 業務分類ノードの label)、 プロジェクトはノードの label、 他はキーそのまま",
" var p = n.props || {};",
" if (by === 'category') { if (n.type === 'Function' && p.categoryNames && p.categoryNames[0]) return String(p.categoryNames[0]); if (n.type === 'Category') return String(n.label); }",
" if (by === 'project' && n.type === 'Project' && n.label) return String(n.label);",
" return key;",
" }",
" CWG.COLOR_FLOWS = COLOR_FLOWS;",
" CWG.colorKeys = function (sub, idx, by) {",
" // ★No.303 (確認NG 2026-10-13): 色は設計書全体のグラフで決める (表示中の近傍だけで伝えると、 深さや表示範囲で色が付いたり消えたりする)。",
" // 出所 (機能の業務分類 大 / データドメインのプロジェクト・責任部門) から COLOR_FLOWS の向きに全体へ伝え、 入れ物の色を子が継ぐ (機能 → ブロック → 画面項目)。",
" // 凡例の名前はプロジェクト / 業務分類のノードから引く (文脈レーンを表示していなくても内部 ID にならない)。 凡例に出すキーは表示中のノードが持つ色だけ。",
" var res = { keyOf: {}, mixed: {}, keys: [], labelOf: {} };",
" if (!by || by === 'type' || !has(COLOR_FLOWS, by)) return res;",
" if (!idx._colorCache) idx._colorCache = {};",
" var all = idx._colorCache[by];",
" if (!all) {",
" all = { sets: {}, labelOf: {} };",
" var sets = all.sets, own = {}, i, id, n, k, flows = COLOR_FLOWS[by], fl = {}, e, src, dst, kk, changed = true, round = 0, lists = [];",
" for (i = 0; i < flows.length; i++) fl[flows[i][0]] = flows[i][1];",
" for (i = 0; i < idx.order.length; i++) {",
" id = idx.order[i]; n = idx.nodes[id]; k = ownColorKey(n, by);",
" if (k) { own[id] = 1; sets[id] = {}; sets[id][k] = 1; if (!has(all.labelOf, k) || all.labelOf[k] === k) all.labelOf[k] = ownColorLabel(n, by, k); }",
" if (idx.out[id]) lists.push(idx.out[id]);",
" }",
" while (changed && round < 12) {",
" changed = false; round++;",
" for (var li = 0; li < lists.length; li++) {",
" var el = lists[li];",
" for (i = 0; i < el.length; i++) {",
" e = el[i]; if (!has(fl, e.type)) continue;",
" src = fl[e.type] === 'out' ? e.from : e.to; dst = fl[e.type] === 'out' ? e.to : e.from;",
" if (!has(sets, src) || has(own, dst)) continue;",
" if (!has(sets, dst)) sets[dst] = {};",
" for (kk in sets[src]) if (has(sets[src], kk) && !has(sets[dst], kk)) { sets[dst][kk] = 1; changed = true; }",
" }",
" }",
" }",
" for (var lv = 0; lv < 2; lv++) { // 入れ物の色を子が継ぐ (機能 → ブロック → 画面項目): 色の無い子だけ",
" for (var li2 = 0; li2 < lists.length; li2++) {",
" var el2 = lists[li2];",
" for (i = 0; i < el2.length; i++) {",
" e = el2[i]; if (!has(CONTAIN, e.type) || e.inferred || !has(sets, e.from) || has(sets, e.to)) continue;",
" sets[e.to] = {}; for (kk in sets[e.from]) if (has(sets[e.from], kk)) sets[e.to][kk] = 1;",
" }",
" }",
" }",
" // 凡例の名前: プロジェクトは project:<キー> のノードの label (複数は ; で並べる)、 業務分類 (大) は cat:L/<コード> のノードの label",
" var lk;",
" for (id in sets) {",
" if (!has(sets, id)) continue;",
" for (lk in sets[id]) {",
" if (!has(sets[id], lk) || (has(all.labelOf, lk) && all.labelOf[lk] !== lk)) continue;",
" all.labelOf[lk] = colorKeyLabel(idx, by, lk);",
" }",
" }",
" idx._colorCache[by] = all;",
" }",
" var seenKey = {}, si, sid, ks;",
" for (si = 0; si < sub.nodes.length; si++) {",
" sid = sub.nodes[si]; if (!has(all.sets, sid)) continue;",
" ks = keys(all.sets[sid]);",
" if (ks.length === 1) res.keyOf[sid] = ks[0]; else if (ks.length > 1) res.mixed[sid] = 1;",
" for (var ki = 0; ki < ks.length; ki++) if (!seenKey[ks[ki]]) { seenKey[ks[ki]] = 1; res.keys.push(ks[ki]); res.labelOf[ks[ki]] = all.labelOf[ks[ki]] || ks[ki]; }",
" }",
" res.keys.sort(function (a, b) { var la = res.labelOf[a], lb = res.labelOf[b]; return la < lb ? -1 : (la > lb ? 1 : (a < b ? -1 : (a > b ? 1 : 0))); });",
" return res;",
" };",
" function colorKeyLabel(idx, by, k) { // キー → 凡例の名前 (全体のグラフのノードから)",
" var parts, i, out = [], n;",
" if (by === 'project') {",
" parts = String(k).split(';');",
" for (i = 0; i < parts.length; i++) { n = idx.nodes['project:' + parts[i]]; out.push(n && n.label ? String(n.label) : parts[i]); }",
" return out.join(' ; ');",
" }",
" if (by === 'category') { n = idx.nodes['cat:L/' + k]; if (n && n.label) return String(n.label); }",
" if (by === 'dept') { n = idx.nodes['dept:' + k]; if (n && n.label) return String(n.label); }",
" return k;",
" }",
"",
" // ---- ブラウザ側の組み立て (Graph.html) ----",
" CWG.mount = function (rootEl, graph, ontology, L, doc) {",
" doc = doc || root.document;",
" function load(key, dflt) { try { var v = root.localStorage.getItem('cwg.' + key); return v == null ? dflt : v; } catch (e) { return dflt; } }",
" function store(key, val) { try { root.localStorage.setItem('cwg.' + key, String(val)); } catch (e) {} }",
" var lang = graph.lang === 'en' ? 'en' : 'ja', idx = CWG.index(graph);",
" var state = { start: null, depth: 2, mode: 'layered', dir: 'both', types: {}, colorBy: 'type', selected: null, edgeLabels: false, inferred: true, inferredTouched: false,",
" spacing: load('spacing', 'auto'), sizeBy: load('sizeBy', 'local'), bundle: load('bundle', '1') !== '0', expanded: {}, hideTypes: {},",
" infStart: load('infStart', '1') !== '0', stopHubs: load('stopHubs', '1') !== '0', noDescend: load('noDescend', '1') !== '0' }; // 2026-10-13 / 10-14: 深さの広げ方 (既定 ON)",
" var htRaw = load('hideTypes', null); if (htRaw == null) htRaw = HIDE_DEFAULT.join(','); // 初回は既定 (物理属性名を隠す)、 以後は覚えた値",
" var htl = String(htRaw).split(','), hti; // 案 B (2026-10-09): 隠す種類は覚える (凡例のチェック)",
" for (hti = 0; hti < htl.length; hti++) if (htl[hti] && has(idx.byType, htl[hti])) state.hideTypes[htl[hti]] = true;",
" if (!has(SPACING, state.spacing) && state.spacing !== 'auto') state.spacing = 'auto';",
" if (state.sizeBy !== 'none' && state.sizeBy !== 'local' && state.sizeBy !== 'global') state.sizeBy = 'local';",
" var et = keys(idx.edgeTypes).sort(), i, curSub = null;",
" for (i = 0; i < et.length; i++) state.types[et[i]] = true;",
" function tl(t) { return (ontology && ontology.nodeTypes && ontology.nodeTypes[t] && ontology.nodeTypes[t].label && ontology.nodeTypes[t].label[lang]) || t; }",
" function el(t) { return (ontology && ontology.edgeTypes && ontology.edgeTypes[t] && ontology.edgeTypes[t].label && ontology.edgeTypes[t].label[lang]) || t; }",
" function opt(v, label, cur) { return '<option value=\"' + esc(v) + '\"' + (v === cur ? ' selected' : '') + '>' + esc(label) + '</option>'; }",
" var html = '';",
" html += '<div class=\"cwg-top\"><label>' + esc(L.start) + ' <input type=\"text\" id=\"cwgQ\" placeholder=\"' + esc(L.startPh) + '\" autocomplete=\"off\"></label><div id=\"cwgSug\" class=\"cwg-sug\" hidden></div>';",
" html += '<label>' + esc(L.mode) + ' <select id=\"cwgMode\"><option value=\"layered\">' + esc(L.layered) + '</option><option value=\"force\">' + esc(L.force) + '</option></select></label>';",
" html += '<label>' + esc(L.depth) + ' <select id=\"cwgDepth\"><option>1</option><option selected>2</option><option>3</option><option>4</option></select></label>';",
" html += '<label>' + esc(L.direction) + ' <select id=\"cwgDir\"><option value=\"both\">' + esc(L.dirBoth) + '</option><option value=\"out\">' + esc(L.dirOut) + '</option><option value=\"in\">' + esc(L.dirIn) + '</option></select></label>';",
" html += '<label>' + esc(L.spacing) + ' <select id=\"cwgSpace\">' + opt('auto', L.spaceAuto, state.spacing) + opt('compact', L.spaceCompact, state.spacing) + opt('normal', L.spaceNormal, state.spacing) + opt('wide', L.spaceWide, state.spacing) + opt('widest', L.spaceWidest, state.spacing) + '</select></label>';",
" html += '<label>' + esc(L.sizeBy) + ' <select id=\"cwgSize\">' + opt('none', L.sizeNone, state.sizeBy) + opt('local', L.sizeLocal, state.sizeBy) + opt('global', L.sizeGlobal, state.sizeBy) + '</select></label>';",
" html += '<label>' + esc(L.colorBy) + ' <select id=\"cwgColor\" title=\"' + esc(L.colorHelp || '') + '\"><option value=\"type\">' + esc(L.colorType) + '</option><option value=\"category\">' + esc(L.colorCategory) + '</option><option value=\"project\">' + esc(L.colorProject) + '</option><option value=\"dept\">' + esc(L.colorDept) + '</option></select></label>';",
" html += '<label><input type=\"checkbox\" id=\"cwgBundle\"' + (state.bundle ? ' checked' : '') + '> ' + esc(L.bundle) + '</label>';",
" html += '<label><input type=\"checkbox\" id=\"cwgEl\"> ' + esc(L.edgeLabels) + '</label>';",
" if (idx.inferred) html += '<label><input type=\"checkbox\" id=\"cwgInf\" checked> ' + esc(L.inferred) + ' <span class=\"cwg-cnt\">' + idx.inferred + '</span></label>';",
" if (idx.inferred) html += '<label title=\"' + esc(L.inferredStartOnlyHelp || '') + '\"><input type=\"checkbox\" id=\"cwgInfStart\"' + (state.infStart ? ' checked' : '') + '> ' + esc(L.inferredStartOnly || 'inferred from start only') + '</label>';",
" html += '<label title=\"' + esc(L.stopHubsHelp || '') + '\"><input type=\"checkbox\" id=\"cwgStopHubs\"' + (state.stopHubs ? ' checked' : '') + '> ' + esc(L.stopHubs || 'stop at context') + '</label>';",
" html += '<label title=\"' + esc(L.noDescendHelp || '') + '\"><input type=\"checkbox\" id=\"cwgNoDescend\"' + (state.noDescend ? ' checked' : '') + '> ' + esc(L.noDescend || 'containers: contents from the start only') + '</label>';",
" html += '<button type=\"button\" id=\"cwgFit\">' + esc(L.fit) + '</button><button type=\"button\" id=\"cwgSave\">' + esc(L.saveSvg) + '</button></div>';",
" html += '<div class=\"cwg-types\" id=\"cwgTypes\">' + esc(L.edgeTypes) + ': ';",
" for (i = 0; i < et.length; i++) html += '<label><input type=\"checkbox\" data-et=\"' + esc(et[i]) + '\" checked> ' + esc(el(et[i])) + ' <span class=\"cwg-cnt\">' + idx.edgeTypes[et[i]] + '</span></label>';",
" html += '</div>';",
" html += '<div class=\"cwg-main\"><div class=\"cwg-canvas\" id=\"cwgCanvas\"><div class=\"cwg-empty\">' + esc(L.empty) + '</div></div><div class=\"cwg-side\" id=\"cwgSide\"><div class=\"cwg-legend\" id=\"cwgLegend\"></div><div id=\"cwgDetail\"></div></div></div>';",
" html += '<div class=\"cwg-status\" id=\"cwgStatus\"></div>';",
" rootEl.innerHTML = html;",
" var q = doc.getElementById('cwgQ'), sug = doc.getElementById('cwgSug'), canvas = doc.getElementById('cwgCanvas'), detail = doc.getElementById('cwgDetail'), status = doc.getElementById('cwgStatus'), legend = doc.getElementById('cwgLegend');",
" // 凡例 (種類は固定。 ★No.303: 色分けが種類以外のときはキーごとの色 + 複数 + 該当なしも出す)",
" var COLOR_PALETTE = ['#2563eb', '#059669', '#d97706', '#7c3aed', '#db2777', '#0891b2', '#65a30d', '#ea580c', '#4f46e5', '#0d9488', '#9333ea', '#b45309'], COLOR_MIXED = '#94a3b8', COLOR_NONE = '#e2e8f0';",
" var tps = keys(idx.byType).sort(function (a, b) { return (LANE_OF[a] || 0) - (LANE_OF[b] || 0) || (a < b ? -1 : 1); });",
" function renderLegend(ck) {",
" var lg = '', i;",
" for (i = 0; i < tps.length; i++) lg += '<label class=\"cwg-lg\" title=\"' + esc(L.typesHelp || '') + '\"><input type=\"checkbox\" data-nt=\"' + esc(tps[i]) + '\"' + (state.hideTypes[tps[i]] ? '' : ' checked') + '> <i style=\"background:' + TYPE_COLOR[tps[i]] + '\"></i>' + esc(tl(tps[i])) + ' <span class=\"cwg-cnt\">' + idx.byType[tps[i]].length + '</span></label>';",
" if (idx.inferred) lg += '<span class=\"cwg-lg\"><i class=\"cwg-lg-dash\"></i>' + esc(L.inferred) + '</span>';",
" lg += '<span class=\"cwg-lg\"><i class=\"cwg-lg-via\"></i>' + esc(L.viaLegend || L.via || 'via') + '</span>';",
" lg += '<span class=\"cwg-lg\"><i class=\"cwg-lg-bundle\"></i>' + esc(L.bundleLegend || L.bundle) + '</span>';",
" if (ck && ck.keys && state.colorBy !== 'type') {",
" var sel = doc.getElementById('cwgColor'), byLabel = sel && sel.options[sel.selectedIndex] ? sel.options[sel.selectedIndex].text : state.colorBy;",
" lg += '<div class=\"cwg-lg-keys\"><b>' + esc(L.colorLegend || 'Colours') + ' (' + esc(byLabel) + ')</b>';",
" for (i = 0; i < ck.keys.length; i++) lg += '<span class=\"cwg-lg\"><i style=\"background:' + COLOR_PALETTE[i % COLOR_PALETTE.length] + '\"></i>' + esc(ck.labelOf[ck.keys[i]] || ck.keys[i]) + '</span>';",
" lg += '<span class=\"cwg-lg\"><i style=\"background:' + COLOR_MIXED + '\"></i>' + esc(L.colorMixed || 'mixed') + '</span><span class=\"cwg-lg\"><i style=\"background:' + COLOR_NONE + ';border:1px solid #cbd5e1\"></i>' + esc(L.colorNone || 'none') + '</span></div>';",
" }",
" legend.innerHTML = lg;",
" }",
" renderLegend(null);",
" function colorOfFor(ck) { // ★No.303: キーごとの色 (凡例と同じ並び)、 混在は灰、 該当なしは薄い灰",
" if (state.colorBy === 'type') return null;",
" var map = {}, i;",
" for (i = 0; i < ck.keys.length; i++) map[ck.keys[i]] = COLOR_PALETTE[i % COLOR_PALETTE.length];",
" return function (n) {",
" var id = n && n.id;",
" if (id != null && has(ck.keyOf, id) && ck.keyOf[id]) return map[ck.keyOf[id]];",
" if (id != null && has(ck.mixed, id)) return COLOR_MIXED;",
" return COLOR_NONE;",
" };",
" }",
" function render() {",
" if (!state.start) return;",
" var allow = null, anyOff = false, k;",
" for (k in state.types) if (has(state.types, k) && !state.types[k]) anyOff = true;",
" if (anyOff) { allow = {}; for (k in state.types) if (has(state.types, k) && state.types[k]) allow[k] = true; }",
" var maxN = state.mode === 'force' ? 300 : 600;",
" var sub = CWG.neighborhood(idx, state.start, { depth: state.depth, edgeTypes: allow, direction: state.dir, maxNodes: maxN, includeInferred: state.inferred,",
" inferredFromStartOnly: state.infStart, hubTypes: state.stopHubs ? HUB_TYPES : null, containersFromStartOnly: state.noDescend });",
" sub = CWG.completeContainers(sub, idx, { hidden: state.hideTypes }); // 案 C: ブロック / 項目が入ったら機能 / ブロックも (深さを消費しない)",
" var hidN = 0, viaN = 0, anyHidden = false;",
" for (k in state.hideTypes) if (has(state.hideTypes, k) && state.hideTypes[k]) anyHidden = true;",
" if (anyHidden) { // 案 B: 隠した種類は除き、 そこを通る経路は経由の点線に",
" var keepH = {}; keepH[state.start] = 1; if (state.selected) keepH[state.selected] = 1;",
" sub = CWG.collapseTypes(sub, idx, state.hideTypes, { keep: keepH });",
" hidN = sub.hidden || 0; viaN = sub.viaCount || 0;",
" }",
" if (state.bundle) { var keep = {}; keep[state.start] = 1; if (state.selected) keep[state.selected] = 1; sub = CWG.bundleLeaves(sub, idx, { minSize: 6, keep: keep, expanded: state.expanded, typeLabel: tl, fmt: L.bundleFmt }); }",
" curSub = sub;",
" var lopts = { spacing: state.spacing, sizeBy: state.sizeBy };",
" var lay = state.mode === 'force' ? CWG.layoutForce(sub, idx, lopts) : CWG.layoutLayered(sub, idx, lopts);",
" var ck = CWG.colorKeys(sub, idx, state.colorBy);",
" canvas.innerHTML = CWG.renderSvg(sub, lay, idx, { L: L, ontology: ontology, lang: lang, startId: state.start, selectedId: state.selected, colorOf: colorOfFor(ck) || undefined, edgeLabels: state.edgeLabels, hiddenTypes: state.hideTypes });",
" renderLegend(ck);",
" var sv0 = canvas.querySelector('svg'); // ★No.299 / 300: 描いた直後の大きさ (viewBox) を覚える。 fit で width / height を 100% にした後も「全体」の基準に使う",
" nat = sv0 ? fitToContent(sv0) : null; // ★No.314: 線の膨らみ (同じレーンの線 / 自己参照の C 字) が箱の外へ出て切れないよう、 描いた中身の範囲まで広げる",
" var st = (L.statusFmt || '{0} / {1}').replace('{0}', sub.nodes.length).replace('{1}', sub.edges.length);",
" if (sub.bundled) st += ' ' + (L.bundledFmt || '{0} in {1}').replace('{0}', sub.bundled).replace('{1}', sub.bundleCount);",
" if (hidN) { // 隠している種類の名前も (例: 非表示 29 (機能) / 経由 2)",
" var hidNm = [], hk2; for (hk2 in state.hideTypes) if (has(state.hideTypes, hk2) && state.hideTypes[hk2] && idx.byType[hk2]) hidNm.push(tl(hk2));",
" st += ' ' + (L.hiddenFmt || '{0} hidden / {1} via').replace('{0}', hidN + (hidNm.length ? ' (' + hidNm.join(' / ') + ')' : '')).replace('{1}', viaN);",
" }",
" if (sub.truncated) st += ' ' + (L.truncated || '').replace('{0}', maxN);",
" status.textContent = st;",
" fit();",
" }",
" var vb = null, svg = null, nat = null;",
" function fit() { // ★No.299: 2 回目以降は width / height が '100%' なので属性からは測れない → render で覚えた nat (描いた大きさ) で全体を収める",
" svg = canvas.querySelector('svg'); if (!svg) return;",
" if (!nat || !(nat.w > 0)) nat = { x: 0, y: 0, w: parseFloat(svg.getAttribute('width')), h: parseFloat(svg.getAttribute('height')) };",
" var w = nat.w, h = nat.h;",
" var cw = canvas.clientWidth || w, ch = canvas.clientHeight || h, sc = Math.min(cw / w, ch / h, 1.5);",
" vb = { x: nat.x || 0, y: nat.y || 0, w: cw / sc, h: ch / sc }; applyVb();",
" svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%');",
" }",
" function applyVb() { if (svg && vb) svg.setAttribute('viewBox', vb.x + ' ' + vb.y + ' ' + vb.w + ' ' + vb.h); }",
" function fitToContent(sv) { // ★No.314: 描いた直後に中身の範囲 (getBBox) を測り、 箱の外へ出た線の分だけ viewBox / width / height を広げる。 戻り = 描いた大きさ (x / y / w / h)",
" var w = parseFloat(sv.getAttribute('width')), h = parseFloat(sv.getAttribute('height')), x0 = 0, y0 = 0, x1 = w, y1 = h, p = 12;",
" try {",
" var bb = sv.getBBox();",
" if (bb && bb.width > 0 && bb.height > 0) { // 箱の外へ出た側だけ広げる (収まっていれば 0 0 W H のまま = 保存の viewBox も従来どおり)",
" if (bb.x < 0) x0 = Math.floor(bb.x - p);",
" if (bb.y < 0) y0 = Math.floor(bb.y - p);",
" if (bb.x + bb.width > w) x1 = Math.ceil(bb.x + bb.width + p);",
" if (bb.y + bb.height > h) y1 = Math.ceil(bb.y + bb.height + p);",
" }",
" } catch (e) {}",
" var nw = x1 - x0, nh = y1 - y0;",
" if (x0 !== 0 || y0 !== 0 || nw !== w || nh !== h) { sv.setAttribute('viewBox', x0 + ' ' + y0 + ' ' + nw + ' ' + nh); sv.setAttribute('width', nw); sv.setAttribute('height', nh); }",
" return { x: x0, y: y0, w: nw, h: nh };",
" }",
" canvas.addEventListener('wheel', function (ev) {",
" if (!svg || !vb) return; ev.preventDefault();",
" var f = ev.deltaY > 0 ? 1.15 : 1 / 1.15, r = canvas.getBoundingClientRect(), mx = vb.x + (ev.clientX - r.left) / r.width * vb.w, my = vb.y + (ev.clientY - r.top) / r.height * vb.h;",
" vb.w *= f; vb.h *= f; vb.x = mx - (ev.clientX - r.left) / r.width * vb.w; vb.y = my - (ev.clientY - r.top) / r.height * vb.h; applyVb();",
" }, { passive: false });",
" var drag = null;",
" canvas.addEventListener('mousedown', function (ev) { if (!svg || !vb) return; drag = { x: ev.clientX, y: ev.clientY, vx: vb.x, vy: vb.y }; });",
" doc.addEventListener('mousemove', function (ev) { if (!drag || !svg) return; var r = canvas.getBoundingClientRect(); vb.x = drag.vx - (ev.clientX - drag.x) / r.width * vb.w; vb.y = drag.vy - (ev.clientY - drag.y) / r.height * vb.h; applyVb(); });",
" doc.addEventListener('mouseup', function () { drag = null; });",
" function showDetail(id) {",
" var v = curSub && curSub.virtual && has(curSub.virtual, id) ? curSub.virtual[id] : null;",
" if (v) { // 束: まとめた要素の一覧 (押すとその要素へ)",
" var hb = '<h3>' + esc(v.label) + '</h3><div class=\"cwg-kv\"><span>' + esc(L.type) + '</span><span>' + esc(tl(v.type)) + '</span><span>' + esc(L.bundleHub || 'hub') + '</span><span><a href=\"#\" data-go=\"' + esc(v.hub) + '\">' + esc(idx.nodes[v.hub] ? idx.nodes[v.hub].label : v.hub) + '</a> (' + esc(el(v.edgeType)) + ')</span></div>';",
" hb += '<p><button type=\"button\" data-expand=\"' + esc(id) + '\">' + esc(L.expand) + '</button></p><h4>' + esc(L.members) + ' (' + v.members.length + ')</h4><ul>';",
" for (var mi = 0; mi < Math.min(v.members.length, 200); mi++) hb += '<li><a href=\"#\" data-go=\"' + esc(v.members[mi]) + '\">' + esc(idx.nodes[v.members[mi]] ? idx.nodes[v.members[mi]].label : v.members[mi]) + '</a></li>';",
" detail.innerHTML = hb + '</ul>'; return;",
" }",
" var n = idx.nodes[id]; if (!n) { detail.innerHTML = ''; return; }",
" var h = '<h3>' + esc(displayLabel(n)) + '</h3><div class=\"cwg-kv\"><span>' + esc(L.type) + '</span><span>' + esc(tl(n.type)) + '</span><span>ID</span><span><code>' + esc(n.id) + '</code></span>';",
" if (idx.deg[id] != null) h += '<span>' + esc(L.degree || 'relations') + '</span><span>' + idx.deg[id] + '</span>';",
" var pk = keys(n.props || {}).sort(), j;",
" for (j = 0; j < pk.length; j++) { var v2 = n.props[pk[j]]; if (v2 == null || v2 === '' || v2 === false || (v2.length === 0)) continue; h += '<span>' + esc(pk[j]) + '</span><span>' + esc(typeof v2 === 'object' ? JSON.stringify(v2) : v2) + '</span>'; }",
" h += '</div>';",
" if (n.url) h += '<p><a href=\"' + esc(n.url) + '\" target=\"_blank\" rel=\"noopener\">' + esc(n.type === 'Category' ? (L.openIndex || L.openDoc) : L.openDoc) + '</a></p>'; // ★No.304: 業務分類は設計書インデックスのその分類へ",
" var outs = idx.out[id] || [], ins = idx.inn[id] || [];",
" h += '<h4>' + esc(L.outEdges) + ' (' + outs.length + ')</h4><ul>';",
" function infMark(e) { return e.inferred ? ' <span class=\"cwg-inf\" title=\"' + esc(e.rule) + '\">(' + esc(L.inferred) + ')</span>' : ''; }",
" for (j = 0; j < Math.min(outs.length, 60); j++) h += '<li>' + esc(el(outs[j].type)) + ' → <a href=\"#\" data-go=\"' + esc(outs[j].to) + '\">' + esc(idx.nodes[outs[j].to].label) + '</a>' + infMark(outs[j]) + '</li>';",
" h += '</ul><h4>' + esc(L.inEdges) + ' (' + ins.length + ')</h4><ul>';",
" for (j = 0; j < Math.min(ins.length, 60); j++) h += '<li><a href=\"#\" data-go=\"' + esc(ins[j].from) + '\">' + esc(idx.nodes[ins[j].from].label) + '</a> → ' + esc(el(ins[j].type)) + infMark(ins[j]) + '</li>';",
" h += '</ul><p><button type=\"button\" data-center=\"' + esc(id) + '\">' + esc(L.center) + '</button></p>';",
" detail.innerHTML = h;",
" }",
" function applySelection() { // 再描画せずに起点 / 選択の強調だけ付け替える (再描画するとダブルクリックの 2 回目が別の要素に落ちる)",
" if (!svg) return;",
" var gs = svg.querySelectorAll('g.cwg-node'), i, g, r, id;",
" for (i = 0; i < gs.length; i++) { g = gs[i]; id = g.getAttribute('data-id'); r = g.querySelector('rect'); if (!r) continue;",
" var isStart = id === state.start, isSel = id === state.selected;",
" r.setAttribute('stroke', isStart ? '#dc2626' : (isSel ? '#f59e0b' : '#334155')); r.setAttribute('stroke-width', (isStart || isSel) ? '2.5' : (g.getAttribute('data-bundle') ? '1.5' : '1')); }",
" var ps = svg.querySelectorAll('path.cwg-edge');",
" for (i = 0; i < ps.length; i++) { var hi = state.selected && (ps[i].getAttribute('data-from') === state.selected || ps[i].getAttribute('data-to') === state.selected);",
" ps[i].setAttribute('stroke', hi ? '#f59e0b' : '#94a3b8'); ps[i].setAttribute('stroke-width', hi ? '2' : (ps[i].getAttribute('data-bundle') ? '2' : '1.2')); }",
" }",
" function expandBundle(id) { state.expanded[id] = 1; state.selected = null; detail.innerHTML = ''; render(); }",
" canvas.addEventListener('click', function (ev) {",
" var g = ev.target; while (g && g !== canvas && !(g.getAttribute && g.getAttribute('data-id'))) g = g.parentNode;",
" if (!g || g === canvas) return;",
" var cid = g.getAttribute('data-id');",
" if (g.getAttribute('data-bundle')) { state.selected = cid; showDetail(cid); applySelection(); return; } // 束: 詳細に一覧と [展開]",
" state.selected = cid; showDetail(cid); applySelection();",
" });",
" canvas.addEventListener('dblclick', function (ev) {",
" var g = ev.target; while (g && g !== canvas && !(g.getAttribute && g.getAttribute('data-id'))) g = g.parentNode;",
" if (!g || g === canvas) return;",
" if (g.getAttribute('data-bundle')) { expandBundle(g.getAttribute('data-id')); return; } // 束はダブルクリックで展開",
" setStart(g.getAttribute('data-id'));",
" });",
" detail.addEventListener('click', function (ev) {",
" var t = ev.target;",
" if (t.getAttribute && t.getAttribute('data-go')) { ev.preventDefault(); var gid = t.getAttribute('data-go'); state.selected = gid; showDetail(gid); if (svg && svg.querySelector('g.cwg-node[data-id=\"' + gid.replace(/\"/g, '\\\\\"') + '\"]')) applySelection(); else render(); }",
" else if (t.getAttribute && t.getAttribute('data-center')) { setStart(t.getAttribute('data-center')); }",
" else if (t.getAttribute && t.getAttribute('data-expand')) { expandBundle(t.getAttribute('data-expand')); }",
" });",
" function setStart(id) { state.start = id; state.selected = id; state.expanded = {}; q.value = idx.nodes[id] ? idx.nodes[id].label : id; sug.hidden = true; showDetail(id); render(); try { root.location.hash = 'n=' + encodeURIComponent(id); } catch (e) {} }",
" // 起点の検索 (★No.301 / 302: 表示名・論理名・物理名・表示項目名・id の部分一致、 全角半角・大小文字を同一視。 並びと上限は CWG.searchNodes)",
" var sidx = CWG.searchIndex(idx), SUG_LIMIT = 40;",
" q.addEventListener('input', function () {",
" var v = q.value, k;",
" if (!normText(v)) { sug.hidden = true; return; }",
" var r = CWG.searchNodes(idx, sidx, v, { limit: SUG_LIMIT }), h = '';",
" for (k = 0; k < r.hits.length; k++) {",
" var n = idx.nodes[r.hits[k].id];",
" h += '<div class=\"cwg-sug-item\" data-id=\"' + esc(r.hits[k].id) + '\"><i style=\"background:' + TYPE_COLOR[n.type] + '\"></i>' + esc(displayLabel(n)) +",
" (r.hits[k].via ? '<span class=\"cwg-sug-sub\">' + esc(r.hits[k].via.text) + '</span>' : '') + ' <span class=\"cwg-cnt\">' + esc(tl(n.type)) + '</span></div>';",
" }",
" if (r.more) h += '<div class=\"cwg-sug-item cwg-sug-more\">' + esc((L.moreHits || '… +{0}').replace('{0}', r.more)) + '</div>';",
" sug.innerHTML = h || '<div class=\"cwg-sug-item\">' + esc(L.noHit) + '</div>'; sug.hidden = false;",
" });",
" sug.addEventListener('click', function (ev) { var t = ev.target; while (t && t !== sug && !(t.getAttribute && t.getAttribute('data-id'))) t = t.parentNode; if (t && t !== sug) setStart(t.getAttribute('data-id')); });",
" doc.getElementById('cwgMode').addEventListener('change', function (ev) {",
" state.mode = ev.target.value;",
" // 関係図では導出した関係を既定オフ (辺が多すぎて密着する)。 利用者が一度でも触っていればその値を保つ",
" var infEl = doc.getElementById('cwgInf');",
" if (infEl && !state.inferredTouched) { state.inferred = (state.mode === 'layered'); infEl.checked = state.inferred; }",
" render();",
" });",
" doc.getElementById('cwgDepth').addEventListener('change', function (ev) { state.depth = parseInt(ev.target.value, 10) || 2; render(); });",
" doc.getElementById('cwgDir').addEventListener('change', function (ev) { state.dir = ev.target.value; render(); });",
" doc.getElementById('cwgSpace').addEventListener('change', function (ev) { state.spacing = ev.target.value; store('spacing', state.spacing); render(); });",
" doc.getElementById('cwgSize').addEventListener('change', function (ev) { state.sizeBy = ev.target.value; store('sizeBy', state.sizeBy); render(); });",
" doc.getElementById('cwgBundle').addEventListener('change', function (ev) { state.bundle = !!ev.target.checked; store('bundle', state.bundle ? '1' : '0'); state.expanded = {}; render(); });",
" doc.getElementById('cwgColor').addEventListener('change', function (ev) { state.colorBy = ev.target.value; render(); });",
" doc.getElementById('cwgEl').addEventListener('change', function (ev) { state.edgeLabels = !!ev.target.checked; render(); });",
" if (doc.getElementById('cwgInf')) doc.getElementById('cwgInf').addEventListener('change', function (ev) { state.inferred = !!ev.target.checked; state.inferredTouched = true; render(); });",
" if (doc.getElementById('cwgInfStart')) doc.getElementById('cwgInfStart').addEventListener('change', function (ev) { state.infStart = !!ev.target.checked; store('infStart', state.infStart ? '1' : '0'); render(); });",
" doc.getElementById('cwgStopHubs').addEventListener('change', function (ev) { state.stopHubs = !!ev.target.checked; store('stopHubs', state.stopHubs ? '1' : '0'); render(); });",
" doc.getElementById('cwgNoDescend').addEventListener('change', function (ev) { state.noDescend = !!ev.target.checked; store('noDescend', state.noDescend ? '1' : '0'); render(); });",
" doc.getElementById('cwgTypes').addEventListener('change', function (ev) { var t = ev.target.getAttribute('data-et'); if (t) { state.types[t] = !!ev.target.checked; render(); } });",
" legend.addEventListener('change', function (ev) { // 案 B: 凡例の種類のチェック = 隠す",
" var t = ev.target && ev.target.getAttribute ? ev.target.getAttribute('data-nt') : null;",
" if (!t) return;",
" state.hideTypes[t] = !ev.target.checked;",
" var hs = [], hk; for (hk in state.hideTypes) if (has(state.hideTypes, hk) && state.hideTypes[hk]) hs.push(hk);",
" store('hideTypes', hs.join(',')); render();",
" });",
" doc.getElementById('cwgFit').addEventListener('click', fit);",
" doc.getElementById('cwgSave').addEventListener('click', function () {",
" if (!svg) return;",
" var clone = svg.cloneNode(true); // ★No.300: 見えている範囲 (viewBox) ではなく描いた全体を保存する",
" var fw = (nat && nat.w > 0) ? nat.w : (clone.viewBox.baseVal.width || parseFloat(svg.getAttribute('width'))), fh = (nat && nat.h > 0) ? nat.h : (clone.viewBox.baseVal.height || parseFloat(svg.getAttribute('height')));",
" clone.setAttribute('viewBox', ((nat && nat.x) || 0) + ' ' + ((nat && nat.y) || 0) + ' ' + fw + ' ' + fh); clone.setAttribute('width', fw); clone.setAttribute('height', fh); // ★No.314: 広げた範囲ごと保存",
" var blob = new Blob(['<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n' + clone.outerHTML], { type: 'image/svg+xml' }), a = doc.createElement('a');",
" a.href = URL.createObjectURL(blob); a.download = 'commonweal-graph.svg'; doc.body.appendChild(a); a.click(); doc.body.removeChild(a);",
" });",
" // URL の #n=<id> で起点を復元 (開いたとき、 戻る / 進む、 ハッシュだけ変えて開き直したとき)",
" function fromHash() { try { var m = /[#&]n=([^&]+)/.exec(root.location.hash || ''); if (m) { var hid = decodeURIComponent(m[1]); if (idx.nodes[hid] && hid !== state.start) setStart(hid); } } catch (e2) {} }",
" fromHash();",
" try { root.addEventListener('hashchange', fromHash); } catch (e3) {}",
" return { state: state, idx: idx, render: render, setStart: setStart };",
" };",
"",
" if (typeof module !== 'undefined' && module.exports) module.exports = CWG;",
" root.CWG = CWG;",
"})(typeof window !== 'undefined' ? window : this);",
].join('\n');
// [[GRAPH-EXPLORER-JS-END]]
TFC.graphExplorerLabels = function (lang) {
return { start: TFC.t('graph.start', lang), startPh: TFC.t('graph.startPh', lang), mode: TFC.t('graph.mode', lang), layered: TFC.t('graph.layered', lang), force: TFC.t('graph.force', lang),
depth: TFC.t('graph.depth', lang), direction: TFC.t('graph.direction', lang), dirBoth: TFC.t('graph.dirBoth', lang), dirOut: TFC.t('graph.dirOut', lang), dirIn: TFC.t('graph.dirIn', lang),
colorBy: TFC.t('graph.colorBy', lang), colorType: TFC.t('graph.colorType', lang), colorCategory: TFC.t('graph.colorCategory', lang), colorProject: TFC.t('graph.colorProject', lang), colorDept: TFC.t('graph.colorDept', lang),
edgeLabels: TFC.t('graph.edgeLabels', lang), fit: TFC.t('graph.fit', lang), saveSvg: TFC.t('graph.saveSvg', lang), edgeTypes: TFC.t('graph.edgeTypes', lang), empty: TFC.t('graph.empty', lang),
statusFmt: TFC.t('graph.status', lang), truncated: TFC.t('graph.truncated', lang), type: TFC.t('graph.type', lang), openDoc: TFC.t('graph.openDoc', lang), outEdges: TFC.t('graph.outEdges', lang),
colorNone: TFC.t('graph.colorNone', lang), colorMixed: TFC.t('graph.colorMixed', lang), colorLegend: TFC.t('graph.colorLegend', lang), colorHelp: TFC.t('graph.colorHelp', lang), moreHits: TFC.t('graph.moreHits', lang), openIndex: TFC.t('graph.openIndex', lang),
inEdges: TFC.t('graph.inEdges', lang), center: TFC.t('graph.center', lang), noHit: TFC.t('graph.noHit', lang), loadError: TFC.t('graph.loadError', lang), inferred: TFC.t('graph.inferred', lang),
spacing: TFC.t('graph.spacing', lang), spaceAuto: TFC.t('graph.spaceAuto', lang), spaceCompact: TFC.t('graph.spaceCompact', lang), spaceNormal: TFC.t('graph.spaceNormal', lang),
spaceWide: TFC.t('graph.spaceWide', lang), spaceWidest: TFC.t('graph.spaceWidest', lang), sizeBy: TFC.t('graph.sizeBy', lang), sizeNone: TFC.t('graph.sizeNone', lang),
sizeLocal: TFC.t('graph.sizeLocal', lang), sizeGlobal: TFC.t('graph.sizeGlobal', lang), bundle: TFC.t('graph.bundle', lang), bundleLegend: TFC.t('graph.bundleLegend', lang),
bundleFmt: TFC.t('graph.bundleFmt', lang), bundledFmt: TFC.t('graph.bundled', lang), bundleHub: TFC.t('graph.bundleHub', lang), expand: TFC.t('graph.expand', lang),
members: TFC.t('graph.members', lang), degree: TFC.t('graph.degree', lang),
via: TFC.t('graph.via', lang), viaLegend: TFC.t('graph.viaLegend', lang), hiddenFmt: TFC.t('graph.hiddenFmt', lang), hiddenNote: TFC.t('graph.hiddenNote', lang), typesHelp: TFC.t('graph.typesHelp', lang),
lanes: { context: TFC.t('graph.lane.context', lang), edm: TFC.t('graph.lane.edm', lang), entity: TFC.t('graph.lane.entity', lang), attribute: TFC.t('graph.lane.attribute', lang), dictionary: TFC.t('graph.lane.dictionary', lang),
table: TFC.t('graph.lane.table', lang), column: TFC.t('graph.lane.column', lang), 'function': TFC.t('graph.lane.function', lang) },
inferredStartOnly: TFC.t('graph.inferredStartOnly', lang), inferredStartOnlyHelp: TFC.t('graph.inferredStartOnlyHelp', lang), stopHubs: TFC.t('graph.stopHubs', lang), stopHubsHelp: TFC.t('graph.stopHubsHelp', lang),
noDescend: TFC.t('graph.noDescend', lang), noDescendHelp: TFC.t('graph.noDescendHelp', lang) };
};
var _GRAPH_EXPLORER_CSS =
'.cwg-lg-dash{display:inline-block;width:18px;height:0;border-top:2px dashed #94a3b8;vertical-align:middle;margin-right:4px}.cwg-inf{color:#64748b;font-size:.9em}' +
'.cwg-lg-via{display:inline-block;width:18px;height:0;border-top:2px dotted #64748b;vertical-align:middle;margin-right:4px}.cwg-lg input{margin:0 1px 0 0}label.cwg-lg{cursor:pointer}' +
'.cwg-lg-bundle{display:inline-block;width:14px;height:10px;border:1.5px dashed #334155;border-radius:3px;vertical-align:middle;margin-right:4px;box-sizing:border-box}' +
'body{margin:0;font-family:"Segoe UI","Hiragino Sans","Yu Gothic UI",Meiryo,sans-serif;font-size:13px;color:#1f2937;background:#f8fafc}' +
'.cwg-page{max-width:1700px;margin:0 auto;padding:14px 18px 24px}.cwg-page h1{font-size:1.3em;margin:0 0 4px;color:#0369a1}.cwg-intro{color:#475569;margin:0 0 10px;font-size:.92em}' +
'.cwg-top{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;position:relative;background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:8px 12px}' +
'.cwg-top label{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}.cwg-top input[type=text]{width:320px;padding:4px 6px;border:1px solid #94a3b8;border-radius:4px}' +
'.cwg-top select{padding:3px 4px;border:1px solid #94a3b8;border-radius:4px}.cwg-top button{padding:4px 10px;border:1px solid #0369a1;background:#0369a1;color:#fff;border-radius:4px;cursor:pointer}' +
'.cwg-sug{position:absolute;top:40px;left:12px;z-index:5;background:#fff;border:1px solid #94a3b8;border-radius:4px;max-height:320px;overflow:auto;min-width:380px;box-shadow:0 6px 18px rgba(0,0,0,.15)}' +
'.cwg-sug-item{padding:4px 10px;cursor:pointer;display:flex;align-items:center;gap:6px}.cwg-sug-item:hover{background:#e0f2fe}.cwg-sug-item i,.cwg-lg i{display:inline-block;width:10px;height:10px;border-radius:2px}' +
'.cwg-types{margin:8px 0;font-size:.9em;color:#334155}.cwg-types label{margin-right:10px;white-space:nowrap}.cwg-cnt{color:#94a3b8;font-size:.85em}' +
'.cwg-main{display:flex;gap:12px;min-height:560px}.cwg-canvas{flex:1 1 auto;background:#fff;border:1px solid #cbd5e1;border-radius:6px;overflow:hidden;position:relative;min-height:560px;user-select:none}' +
'.cwg-canvas svg{display:block}.cwg-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#94a3b8}' +
'.cwg-side{flex:0 0 340px;background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:10px 12px;overflow:auto;max-height:80vh}' +
'.cwg-legend{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:.85em;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid #e2e8f0}.cwg-lg{display:inline-flex;align-items:center;gap:5px}' +
'.cwg-side h3{margin:4px 0 6px;font-size:1.05em;color:#0369a1}.cwg-side h4{margin:10px 0 4px;font-size:.95em;color:#334155}.cwg-side ul{margin:0;padding-left:1.2em}.cwg-side li{margin:2px 0}' +
'.cwg-kv{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;font-size:.9em}.cwg-kv span:nth-child(odd){color:#64748b;white-space:nowrap}.cwg-kv code{font-size:.9em;word-break:break-all}' +
'.cwg-side button{padding:3px 8px;border:1px solid #0369a1;background:#fff;color:#0369a1;border-radius:4px;cursor:pointer}.cwg-status{margin-top:6px;color:#64748b;font-size:.88em}.cwg-foot{margin-top:10px}' +
'.cwg-sug-sub{color:#64748b;font-size:.85em;margin-left:6px}.cwg-sug-more{color:#64748b;font-style:italic;cursor:default}.cwg-lg-keys{margin-top:4px}.cwg-lg-keys b{font-weight:600;margin-right:6px;color:#334155}';
// Graph.html (全プラン)。 検索バーは呼び手 (TFC.searchInject) が差し込む。 ★extra.headCss / headHtml = 呼び手 (update-before) が渡す他ページと同じヘッダのリンク (2026-10-08)
TFC.graphExplorerHtml = function (lang, extra) {
var L = TFC.graphExplorerLabels(lang);
var ex = extra || {};
return '<!DOCTYPE html><html lang="' + (lang === 'en' ? 'en' : 'ja') + '"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">' +
'<title>' + TFC.escapeHtml(TFC.t('graph.title', lang)) + '</title><style>' + _GRAPH_EXPLORER_CSS + (ex.headCss || '') + '</style></head><body>' +
'<div class="cwg-page"><h1>' + TFC.escapeHtml(TFC.t('graph.title', lang)) + '</h1>' + (ex.headHtml || '') + '<p class="cwg-intro">' + TFC.escapeHtml(TFC.t('graph.intro', lang)) + '</p>' +
'<div id="cwgRoot"><div class="cwg-empty">' + TFC.escapeHtml(TFC.t('graph.empty', lang)) + '</div></div>' +
'<p class="cwg-foot"><a href="index.html">' + TFC.escapeHtml(TFC.t('graph.backHub', lang)) + '</a></p></div>' +
'<script src="graph-data.js"></script>' +
'<script>' + _GRAPH_EXPLORER_JS + '</script>' +
'<script>(function(){var L=' + JSON.stringify(L) + ';var g=window.CW_GRAPH,o=window.CW_ONTOLOGY,r=document.getElementById("cwgRoot");' +
'if(!g||!window.CWG){r.innerHTML="<p class=\\"cwg-empty\\" style=\\"position:static\\">"+L.loadError+"</p>";return;}window.CWG.mount(r,g,o,L);})();</script>' +
'</body></html>';
};
// ============================================================
// ★Ver1.0.23: GraphRAG の静的ファイル (meta/graphrag/ の README / LlamaIndex の例 / コミュニティ要約ツール)
// ============================================================
// 正本 = src/common/graphrag/ (tools/embed_mcp_server.py が下のブロックに文字列として埋め込む)。 製品は LLM を呼ばない (読み取り専用、 外へ送らない)。
// ★MCP サーバ (meta/mcp/commonweal-mcp.js + README.md) の同梱は 2026-10-09 に廃止 (ユーザー決定): MCP サーバとしての提供は TALON AI Connect に統合し、
// 道具の論理は src/common/mcp/commonweal-graph-core.js (依存無しのコア) に残す。 マーカー名 [[MCP-SERVER-*]] は互換のため据え置き。
// [[MCP-SERVER-BEGIN]]
// GraphRAG の静的ファイル (meta/graphrag/ の README / LlamaIndex の例 / コミュニティ要約ツール)。 正本 = src/common/graphrag/、 tools/embed_mcp_server.py が埋め込む (手で編集しない)。 ★MCP サーバの同梱は 2026-10-09 に廃止 (TALON AI Connect に統合)
var _GRAPHRAG_README_MD = [
"# GraphRAG 素材 / GraphRAG materials",
"",
"このフォルダは、設計書の知識グラフ (`meta/graph/graph.json`) を GraphRAG のツールに取り込むための素材です。製品は LLM を呼びません。ここにあるのはデータと取り込み例だけで、質問に答えるのは利用者の AI クライアントです。",
"",
"This folder holds the materials for loading the knowledge graph of the design documents (`meta/graph/graph.json`) into GraphRAG tools. The product never calls an LLM: this is data plus loading examples; answering questions is the job of your AI client.",
"",
"## 中身 / Contents",
"",
"| ファイル / file | 内容 / what it is |",
"|---|---|",
"| `text_units.json` | `meta/*.md` を見出しで区切った文書断片。各断片に、言及している知識グラフのノード id (`entities`) が付く / the Markdown documents split by heading, each chunk linked to the graph nodes it mentions |",
"| `neo4j/nodes.csv`, `neo4j/edges.csv`, `neo4j/import.cypher` | Neo4j の `LOAD CSV` で取り込む CSV と Cypher / CSV files and the Cypher script for Neo4j `LOAD CSV` |",
"| `llamaindex_example.py` | LlamaIndex の `PropertyGraphIndex` にグラフと文書断片を入れる例 / example that builds a LlamaIndex `PropertyGraphIndex` from the graph and the text units |",
"",
"グラフ本体は `../graph/graph.json` (プロパティグラフ) と `../ontology/graph.ttl` (RDF)、語彙は `../graph/ontology.json` / `../ontology/ontology.ttl` です。",
"",
"## ローカル検索はそのまま使える / Local search is built in",
"",
"ローカル検索 (質問 → 実体の順位付け → その関係 → 文書断片 → 文脈パック) の手順は、text_units.json と graph.json だけで組めます: 質問の語を実体の名前 (label / 論理名 / 物理名 / 定義) と文書断片の本文で当て、当たった実体の関係 (出入りのエッジ、導出した関係は inferred 印つき) と文書断片を集めてプロンプトに入れます。MCP サーバとしての提供 (`cw_context`) は TALON AI Connect に統合します (設計書 ZIP への MCP サーバの同梱は 2026-10-09 に廃止)。",
"",
"The local-search recipe (question → ranked entities → their relations → text chunks → context pack) needs only text_units.json and graph.json: match the query words against entity names (label / logical / physical name / definition) and chunk texts, then collect the relations of the matched entities (edges in both directions; inferred ones are flagged) and the chunks into the prompt. As an MCP tool (`cw_context`) it is provided by TALON AI Connect (the MCP server is no longer bundled in the ZIP since 2026-10-09).",
"",
"## Neo4j",
"",
"1. `neo4j/nodes.csv` と `neo4j/edges.csv` を Neo4j の import フォルダに置く (Neo4j Desktop: データベースの「Open folder → Import」/ Docker: `/var/lib/neo4j/import`)。",
"2. `neo4j/import.cypher` を Neo4j Browser か `cypher-shell -f neo4j/import.cypher` で実行する。",
"3. 例: `MATCH (f:Function)-[:reads]->(t:Table) RETURN f.label, t.label LIMIT 20`",
"",
"ノードのラベルは種類 (`Function` / `Table` / `Column` / `DataDomain` / `EdmEntity` …) と共通の `CW`、関係の型は `meta/graph/ontology.json` の edgeTypes と同じ名前です。属性は `props` に JSON 文字列で入ります (APOC があれば `apoc.convert.fromJsonMap(n.props)`)。導出した関係は `inferred = true` と `rule` を持ちます。",
"",
"Put `neo4j/nodes.csv` and `neo4j/edges.csv` into the Neo4j import folder, run `neo4j/import.cypher` (Neo4j Browser or `cypher-shell -f`), then query, e.g. `MATCH (f:Function)-[:reads]->(t:Table) RETURN f.label, t.label LIMIT 20`. Node labels are the node types plus `CW`; relationship types are the edge type names of `meta/graph/ontology.json`; properties are a JSON string in `props`; inferred relations carry `inferred = true` and `rule`.",
"",
"## LlamaIndex",
"",
"```bash",
"pip install llama-index-core",
"python llamaindex_example.py # グラフを組んで近傍を引く (LLM 不要) / build the graph store and query neighbours (no LLM needed)",
"```",
"",
"スクリプトの中のコメントに、LLM や埋め込みモデルをつないで `PropertyGraphIndex` の検索 (`as_retriever`) を使う方法を書いてあります。",
"",
"The comments in the script show how to attach an LLM / embedding model and use `PropertyGraphIndex` retrieval (`as_retriever`).",
"",
"## コミュニティ要約とグローバル検索 / Community summaries and global search",
"",
"GraphRAG のグローバル検索 (「このシステム全体で何が重要か」のような大局的な質問) には、グラフをまとまり (コミュニティ) に分けて要約した「コミュニティレポート」が要ります。`communities.py` がそれを作ります。",
"",
"1. `python communities.py` (引数なしで設計書のフォルダ) → `communities.json`。構造から決定的に作ります (LLM 不要): 業務分類 (大 → 中 → 小) / EDM (→ エンティティ) / 責任部門ごとの業務データ辞書。各コミュニティに所属ノード・関係・文書断片が付きます。",
"2. `python communities.py --summarize` → `community_reports.json`。各コミュニティの要約と所見を LLM に書かせます。利用者の API キーを環境変数で渡します (`ANTHROPIC_API_KEY` か `OPENAI_API_KEY`。`--provider` / `--model` / `--max N` / `--level 0`)。済みのものは飛ばします (`--force` で作り直し)。",
"3. `python communities.py --msgraphrag out_dir` → Microsoft GraphRAG の索引テーブル (`entities` / `relationships` / `communities` / `community_reports` / `text_units` / `documents`。pyarrow があれば parquet、無ければ CSV)。GraphRAG の `query` にかけるには、さらに GraphRAG 側で埋め込み (ベクトル) の工程が要ります。",
"",
"GraphRAG global search (big-picture questions such as \"what matters most in this system\") needs community reports: the graph split into communities, each summarized. `communities.py` builds them: (1) deterministic communities from the structure (business categories L → M → S, EDMs → entities, the data dictionary by department) into `communities.json`, no LLM; (2) `--summarize` writes summaries and findings with your own API key (`ANTHROPIC_API_KEY` or `OPENAI_API_KEY`; `--provider`, `--model`, `--max`, `--level`; existing reports are kept unless `--force`); (3) `--msgraphrag out_dir` exports the Microsoft GraphRAG index tables (parquet with pyarrow, otherwise CSV). Running GraphRAG `query` on them additionally needs GraphRAG's own embedding step.",
"",
"製品本体は LLM を呼びません。要約を書くのも、文脈パックを使って答えるのも、利用者側の AI です。",
"",
"The product itself never calls an LLM; writing summaries and answering from the context pack is done on your side.",
].join('\n');
var _GRAPHRAG_LLAMAINDEX_PY = [
"# -*- coding: utf-8 -*-",
"\"\"\"Commonweal の知識グラフ (meta/graph/graph.json) と文書断片 (meta/graphrag/text_units.json) を LlamaIndex の PropertyGraphIndex に入れる例。",
"LLM も埋め込みモデルも無しで動く (グラフストアを組んで近傍を引くところまで)。 検索 (as_retriever) に進むときはコメントのとおり LLM / 埋め込みをつなぐ。",
"",
" pip install llama-index-core",
" python llamaindex_example.py [設計書を展開したフォルダ]",
"",
"Build a LlamaIndex PropertyGraphIndex from the Commonweal knowledge graph (meta/graph/graph.json) and the text units (meta/graphrag/text_units.json).",
"Runs without an LLM or embedding model (graph store + neighbour lookup); see the comments to attach them for retrieval.",
"\"\"\"",
"import json",
"import os",
"import sys",
"",
"from llama_index.core import PropertyGraphIndex, Settings",
"from llama_index.core.graph_stores import SimplePropertyGraphStore",
"from llama_index.core.graph_stores.types import EntityNode, Relation",
"from llama_index.core.schema import TextNode",
"",
"ROOT = sys.argv[1] if len(sys.argv) > 1 else os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))",
"",
"",
"def _graph_json(root):",
" p = os.path.join(root, 'meta', 'graph', 'graph.json') # 無ければ初版 (1.0.23) のフラットな置き場 / falls back to the flat layout of the first release",
" return p if os.path.exists(p) else os.path.join(root, 'meta', 'graph.json')",
"",
"",
"GRAPH = json.load(open(_graph_json(ROOT), encoding='utf-8'))",
"try:",
" UNITS = json.load(open(os.path.join(ROOT, 'meta', 'graphrag', 'text_units.json'), encoding='utf-8'))['units']",
"except OSError:",
" UNITS = []",
"",
"# 1. 実体 (ノード) と関係 (エッジ) をグラフストアへ / entities and relations into the graph store",
"store = SimplePropertyGraphStore()",
"entities = []",
"for n in GRAPH['nodes']:",
" props = {k: v for k, v in (n.get('props') or {}).items() if v not in (None, '', [], False)}",
" props['url'] = n.get('url') or ''",
" entities.append(EntityNode(name=n['id'], label=n['type'], properties=dict(props, display=n.get('label') or n['id'])))",
"relations = []",
"for e in GRAPH['edges']:",
" props = dict(e.get('props') or {})",
" if e.get('inferred'):",
" props.update({'inferred': True, 'rule': e.get('rule'), 'via': ' / '.join(e.get('via') or [])})",
" relations.append(Relation(label=e['type'], source_id=e['from'], target_id=e['to'], properties=props))",
"store.upsert_nodes(entities)",
"store.upsert_relations(relations)",
"",
"# 2. 文書断片を、 言及している実体に結ぶ / text units linked to the entities they mention",
"text_nodes = []",
"for u in UNITS:",
" tn = TextNode(id_=u['id'], text=(u.get('heading') or '') + '\\n' + u['text'], metadata={'doc': u['doc'], 'heading': u.get('heading') or ''})",
" text_nodes.append(tn)",
" for ent in u.get('entities') or []:",
" store.upsert_relations([Relation(label='MENTIONS', source_id=tn.id_, target_id=ent, properties={})])",
"store.upsert_llama_nodes(text_nodes)",
"",
"# 3. LLM / 埋め込み無しで索引を組む / build the index without an LLM or embeddings",
"Settings.llm = None",
"Settings.embed_model = None",
"index = PropertyGraphIndex.from_existing(property_graph_store=store, llm=None, embed_model=None, embed_kg_nodes=False)",
"",
"# 4. 近傍を引く (例: 最初の機能) / neighbours of the first function (no LLM needed)",
"funcs = [n for n in GRAPH['nodes'] if n['type'] == 'Function' and not (n.get('props') or {}).get('external')]",
"print('nodes:', len(entities), 'relations:', len(relations), 'text units:', len(text_nodes))",
"if funcs:",
" fid = funcs[0]['id']",
" start = store.get(ids=[fid])",
" print('neighbours of', fid, '(' + funcs[0]['label'] + ')')",
" for src, rel, dst in store.get_rel_map(start, depth=1, limit=30)[:30]:",
" print(' ', src.id, '-[', rel.label, ']->', dst.id)",
"",
"# 5. 検索に進むとき / to retrieve with an LLM:",
"# from llama_index.llms.openai import OpenAI # or llama_index.llms.anthropic.Anthropic",
"# from llama_index.embeddings.openai import OpenAIEmbedding",
"# Settings.llm = OpenAI(model='gpt-4o-mini'); Settings.embed_model = OpenAIEmbedding()",
"# index = PropertyGraphIndex.from_existing(property_graph_store=store, embed_kg_nodes=True)",
"# retriever = index.as_retriever(include_text=True, similarity_top_k=5)",
"# for node in retriever.retrieve('受注番号はどの画面で使われているか'):",
"# print(node.score, node.text[:200])",
].join('\n');
var _GRAPHRAG_COMMUNITIES_PY = [
"# -*- coding: utf-8 -*-",
"\"\"\"Commonweal GraphRAG: コミュニティ (まとまり) と要約 / communities and community summaries",
"",
"製品は LLM を呼ばない。 このスクリプトは設計書を展開したフォルダで利用者が動かす:",
" 1. 構造からコミュニティを作る (LLM 不要、 決定的): 業務分類 (大 → 中 → 小) / EDM (→ エンティティ) / 責任部門ごとの業務データ辞書",
" 2. --summarize: 各コミュニティの要約を LLM に書かせる (利用者の API キー。 ANTHROPIC_API_KEY か OPENAI_API_KEY)",
" 3. --msgraphrag DIR: Microsoft GraphRAG の索引テーブル (entities / relationships / communities / community_reports / text_units / documents) に書き出す",
"",
" python communities.py [設計書を展開したフォルダ] → meta/graphrag/communities.json",
" python communities.py [dir] --summarize [--provider anthropic|openai] [--model M] [--max N] [--level L]",
" → meta/graphrag/community_reports.json (済みのものは飛ばす。 --force で作り直し)",
" python communities.py [dir] --msgraphrag out_dir → parquet (pyarrow があれば) か CSV",
"",
"The product never calls an LLM; run this in the extracted bundle: (1) deterministic communities from the structure (business categories, EDMs and their",
"entities, the data dictionary by department), (2) --summarize writes summaries with your own API key, (3) --msgraphrag exports the Microsoft GraphRAG index tables.",
"\"\"\"",
"import argparse",
"import csv",
"import datetime",
"import json",
"import os",
"import re",
"import sys",
"import time",
"import urllib.error",
"import urllib.request",
"",
"sys.stdout.reconfigure(encoding='utf-8', errors='replace')",
"",
"",
"def _graph_json(root):",
" p = os.path.join(root, 'meta', 'graph', 'graph.json') # 無ければ初版 (1.0.23) のフラットな置き場 / falls back to the flat layout of the first release",
" return p if os.path.exists(p) else os.path.join(root, 'meta', 'graph.json')",
"",
"",
"def load(root):",
" g = json.load(open(_graph_json(root), encoding='utf-8'))",
" try:",
" tu = json.load(open(os.path.join(root, 'meta', 'graphrag', 'text_units.json'), encoding='utf-8'))['units']",
" except OSError:",
" tu = []",
" return g, tu",
"",
"",
"class Index:",
" def __init__(self, g, units):",
" self.g = g",
" self.nodes = {n['id']: n for n in g['nodes']}",
" self.out, self.inn = {}, {}",
" for i, e in enumerate(g['edges']):",
" e['_i'] = i",
" self.out.setdefault(e['from'], []).append(e)",
" self.inn.setdefault(e['to'], []).append(e)",
" self.units = units",
" self.units_of = {}",
" for u in units:",
" for ent in u.get('entities') or []:",
" self.units_of.setdefault(ent, []).append(u['id'])",
"",
" def step(self, ids, types, direction='out'):",
" out = set()",
" for i in ids:",
" lst = self.out.get(i, []) if direction == 'out' else self.inn.get(i, [])",
" for e in lst:",
" if e['type'] in types:",
" out.add(e['to'] if direction == 'out' else e['from'])",
" return out",
"",
" def by_type(self, t):",
" return [n['id'] for n in self.g['nodes'] if n['type'] == t]",
"",
"",
"def function_members(ix, funcs):",
" \"\"\"機能の集合 → 機能と、 そのブロック / 項目 / 読み書きするテーブル / 格納先と照合された列 / 扱うデータドメイン / 扱うエンティティ\"\"\"",
" m = set(funcs)",
" blocks = ix.step(funcs, {'hasBlock'})",
" items = ix.step(blocks, {'hasItem'})",
" tables = ix.step(funcs, {'reads', 'writes'}) | ix.step(blocks, {'updates'})",
" cols = ix.step(items, {'storesIn'})",
" domains = ix.step(funcs, {'usesDomain'}) | ix.step(items, {'itemMatches'}) | ix.step(cols, {'matchesDomain'})",
" ents = ix.step(funcs, {'handlesEntity'}) | ix.step(tables, {'mapsTo'}, 'in')",
" return m | blocks | items | tables | cols | domains | ents",
"",
"",
"def build_communities(ix, lang):",
" ja = lang != 'en'",
" comms = []",
"",
" def add(key, level, title, members, parent=None, kind=''):",
" members = sorted(x for x in members if x in ix.nodes)",
" if not members:",
" return None",
" ms = set(members)",
" rel = sorted(e['_i'] for e in ix.g['edges'] if e['from'] in ms and e['to'] in ms)",
" tus = sorted({u for m in members for u in ix.units_of.get(m, [])})",
" c = {'key': key, 'level': level, 'title': title, 'kind': kind, 'parent': parent, 'children': [], 'members': members, 'relationships': rel, 'text_units': tus, 'size': len(members)}",
" comms.append(c)",
" return c",
"",
" # 業務分類: 大 (level 0) → 中 (1) → 小 (2)。 配下の機能はその分類かその子孫に belongsTo",
" cats = ix.by_type('Category')",
" parent_of = {}",
" for c in cats:",
" for e in ix.out.get(c, []):",
" if e['type'] == 'childOf':",
" parent_of[c] = e['to']",
" def descendants(c):",
" d, q = {c}, [c]",
" while q:",
" x = q.pop()",
" for k, p in parent_of.items():",
" if p == x and k not in d:",
" d.add(k); q.append(k)",
" return d",
" def funcs_under(c):",
" return ix.step(descendants(c), {'belongsTo'}, 'in')",
" keyed = {}",
" for level_name in ('L', 'M', 'S'):",
" for c in sorted(cats):",
" n = ix.nodes[c]",
" if n['props'].get('level') != level_name:",
" continue",
" fs = funcs_under(c)",
" if not fs:",
" continue",
" lvl = {'L': 0, 'M': 1, 'S': 2}[level_name]",
" par = keyed.get(parent_of.get(c))",
" cm = add(c, lvl, (n['props'].get('name') or n['label']) + (' (業務分類)' if ja else ' (business category)'), function_members(ix, fs) | {c}, par['key'] if par else None, 'category')",
" if cm:",
" keyed[c] = cm",
" if par:",
" par['children'].append(cm['key'])",
" # 業務分類の無い機能",
" rest = [f for f in ix.by_type('Function') if not ix.nodes[f]['props'].get('external') and not ix.step([f], {'belongsTo'})]",
" if rest:",
" add('cat:none', 0, '業務分類の無い機能' if ja else 'Functions without a business category', function_members(ix, rest), None, 'category')",
" # EDM (level 0) → エンティティ (level 1)",
" for edm in sorted(ix.by_type('Edm')):",
" ents = ix.step([edm], {'hasEntity'})",
" attrs = ix.step(ents, {'hasAttribute'})",
" tables = ix.step(ents, {'mapsTo'})",
" doms = ix.step(attrs, {'declares'}, 'in')",
" cm = add(edm, 0, ix.nodes[edm]['label'] + (' (EDM)'), {edm} | ents | attrs | tables | doms, None, 'edm')",
" if not cm:",
" continue",
" for ent in sorted(ents):",
" a = ix.step([ent], {'hasAttribute'})",
" ce = add(ent, 1, ix.nodes[ent]['label'] + (' (エンティティ)' if ja else ' (entity)'), {ent} | a | ix.step([ent], {'mapsTo'}) | ix.step(a, {'declares'}, 'in') | ix.step([ent], {'references', 'subtypeOf'}) | ix.step([ent], {'references', 'subtypeOf'}, 'in'), edm, 'entity')",
" if ce:",
" cm['children'].append(ce['key'])",
" # 業務データ辞書: 責任部門ごと (level 0)",
" doms_all = ix.by_type('DataDomain')",
" by_dept = {}",
" for d in doms_all:",
" by_dept.setdefault(ix.nodes[d]['props'].get('dept') or '', []).append(d)",
" for dept in sorted(by_dept):",
" ds = set(by_dept[dept])",
" members = ds | ix.step(ds, {'hasPhysAttr'}) | ix.step(ds, {'matchesDomain', 'itemMatches'}, 'in') | ix.step(ds, {'declares', 'appearsIn'}) | ix.step(ds, {'ownedBy'})",
" title = ((dept + ' の業務データ辞書') if dept else '責任部門の無いデータドメイン') if ja else ((dept + ' data dictionary') if dept else 'Data domains without a department')",
" add('dept:' + (dept or 'none'), 0, title, members, None, 'dictionary')",
" for i, c in enumerate(comms):",
" c['community'] = i",
" return comms",
"",
"",
"# ---------------- LLM (利用者の API キー) ----------------",
"def llm_call(provider, model, system, user):",
" if provider == 'anthropic':",
" key = os.environ.get('ANTHROPIC_API_KEY')",
" if not key:",
" raise SystemExit('ANTHROPIC_API_KEY is not set')",
" req = urllib.request.Request('https://api.anthropic.com/v1/messages', method='POST', headers={'content-type': 'application/json', 'x-api-key': key, 'anthropic-version': '2023-06-01'},",
" data=json.dumps({'model': model or 'claude-sonnet-5', 'max_tokens': 2000, 'system': system, 'messages': [{'role': 'user', 'content': user}]}).encode('utf-8'))",
" body = json.loads(urllib.request.urlopen(req, timeout=180).read().decode('utf-8'))",
" return ''.join(c.get('text', '') for c in body.get('content', []))",
" key = os.environ.get('OPENAI_API_KEY')",
" if not key:",
" raise SystemExit('OPENAI_API_KEY is not set')",
" req = urllib.request.Request('https://api.openai.com/v1/chat/completions', method='POST', headers={'content-type': 'application/json', 'authorization': 'Bearer ' + key},",
" data=json.dumps({'model': model or 'gpt-4o-mini', 'messages': [{'role': 'system', 'content': system}, {'role': 'user', 'content': user}], 'temperature': 0}).encode('utf-8'))",
" body = json.loads(urllib.request.urlopen(req, timeout=180).read().decode('utf-8'))",
" return body['choices'][0]['message']['content']",
"",
"",
"def llm_json(provider, model, system, user):",
" for attempt in range(4):",
" try:",
" text = llm_call(provider, model, system, user)",
" except urllib.error.HTTPError as e:",
" if e.code in (429, 500, 502, 503, 529) and attempt < 3:",
" time.sleep(5 * (attempt + 1))",
" continue",
" raise SystemExit('LLM error %s: %s' % (e.code, e.read().decode('utf-8', 'replace')[:500]))",
" m = re.search(r'\\{[\\s\\S]*\\}', text)",
" if m:",
" try:",
" return json.loads(m.group(0))",
" except ValueError:",
" pass",
" if attempt == 3:",
" return {'title': '', 'summary': text.strip(), 'findings': [], 'rating': 0, 'rating_explanation': 'unparsed'}",
" return {}",
"",
"",
"def community_prompt(ix, c, lang):",
" ja = lang != 'en'",
" lines = []",
" by_t = {}",
" for m in c['members']:",
" n = ix.nodes[m]",
" by_t.setdefault(n['type'], []).append(n)",
" for t in sorted(by_t):",
" lines.append('## ' + t + ' (' + str(len(by_t[t])) + ')')",
" for n in by_t[t][:60]:",
" p = n.get('props') or {}",
" desc = p.get('definition') or p.get('outline') or p.get('comment') or p.get('logicalName') or ''",
" lines.append('- ' + n['label'] + ' [' + n['id'] + ']' + ((': ' + str(desc)[:200]) if desc else ''))",
" if len(by_t[t]) > 60:",
" lines.append('- ... (' + str(len(by_t[t]) - 60) + ' more)')",
" lines.append('## relations (' + str(len(c['relationships'])) + ')')",
" cnt = {}",
" for i in c['relationships']:",
" cnt[ix.g['edges'][i]['type']] = cnt.get(ix.g['edges'][i]['type'], 0) + 1",
" lines.append(', '.join(k + ': ' + str(v) for k, v in sorted(cnt.items())))",
" for i in c['relationships'][:40]:",
" e = ix.g['edges'][i]",
" lines.append('- ' + ix.nodes[e['from']]['label'] + ' -' + e['type'] + '-> ' + ix.nodes[e['to']]['label'] + (' (inferred)' if e.get('inferred') else ''))",
" units = {u['id']: u for u in ix.units}",
" if c['text_units']:",
" lines.append('## text')",
" for uid in c['text_units'][:6]:",
" u = units.get(uid)",
" if u:",
" lines.append('### ' + u['doc'] + (' — ' + u['heading'] if u.get('heading') else ''))",
" lines.append(u['text'][:600])",
" system = ('あなたはシステムの設計知を要約するアナリストです。 与えられた知識グラフの一部 (コミュニティ) について、 日本語で JSON だけを返してください: '",
" '{\"title\": 短い題名, \"summary\": 全体像を 5〜8 文で, \"findings\": [{\"summary\": 一文, \"explanation\": 根拠を 2〜4 文}] (3〜6 個), \"rating\": 1〜10 の重要度, \"rating_explanation\": 一文}。 '",
" '書かれていないことは推測しないでください。' if ja else",
" 'You are an analyst summarizing the design knowledge of a system. For the given part (community) of a knowledge graph, return JSON only: '",
" '{\"title\": short title, \"summary\": the big picture in 5-8 sentences, \"findings\": [{\"summary\": one sentence, \"explanation\": 2-4 sentences of evidence}] (3-6 items), '",
" '\"rating\": importance 1-10, \"rating_explanation\": one sentence}. Do not invent what is not stated.')",
" return system, '# ' + c['title'] + '\\n\\n' + '\\n'.join(lines)",
"",
"",
"def summarize(root, ix, comms, args):",
" out_path = os.path.join(root, args.out, 'community_reports.json')",
" reports = {}",
" if os.path.exists(out_path) and not args.force:",
" for r in json.load(open(out_path, encoding='utf-8')).get('reports', []):",
" reports[r['key']] = r",
" todo = [c for c in comms if (args.level is None or c['level'] <= args.level) and c['key'] not in reports]",
" if args.max:",
" todo = todo[:args.max]",
" print('summarize %d communities with %s (%s)' % (len(todo), args.provider, args.model or 'default model'))",
" for i, c in enumerate(todo):",
" system, user = community_prompt(ix, c, ix.g.get('lang', 'ja'))",
" res = llm_json(args.provider, args.model, system, user)",
" reports[c['key']] = {'key': c['key'], 'community': c['community'], 'level': c['level'], 'title': res.get('title') or c['title'], 'summary': res.get('summary', ''),",
" 'findings': res.get('findings', []), 'rating': res.get('rating', 0), 'rating_explanation': res.get('rating_explanation', ''),",
" 'model': args.model or ('claude-sonnet-5' if args.provider == 'anthropic' else 'gpt-4o-mini'), 'created': datetime.datetime.now().isoformat(timespec='seconds')}",
" print(' [%d/%d] %s → %s' % (i + 1, len(todo), c['title'], (res.get('title') or '')[:60]))",
" json.dump({'schema': 'commonweal-community-reports/1', 'lang': ix.g.get('lang'), 'reports': [reports[c2['key']] for c2 in comms if c2['key'] in reports]}, open(out_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)",
" return reports",
"",
"",
"# ---------------- Microsoft GraphRAG index tables ----------------",
"def write_table(path_base, rows, columns):",
" rows = [{c: r.get(c) for c in columns} for r in rows]",
" try:",
" import pyarrow as pa",
" import pyarrow.parquet as pq",
" table = pa.Table.from_pylist(rows) if rows else pa.table({c: pa.array([], pa.string()) for c in columns}) # 空でも列名は残す",
" pq.write_table(table, path_base + '.parquet')",
" return path_base + '.parquet'",
" except ImportError:",
" with open(path_base + '.csv', 'w', encoding='utf-8', newline='') as f:",
" w = csv.DictWriter(f, fieldnames=columns)",
" w.writeheader()",
" for r in rows:",
" w.writerow({k: (json.dumps(v, ensure_ascii=False) if isinstance(v, (list, dict)) else v) for k, v in r.items()})",
" return path_base + '.csv'",
"",
"",
"def export_msgraphrag(ix, comms, reports, out_dir, lang):",
" os.makedirs(out_dir, exist_ok=True)",
" today = datetime.date.today().isoformat()",
" degree = {}",
" for e in ix.g['edges']:",
" degree[e['from']] = degree.get(e['from'], 0) + 1",
" degree[e['to']] = degree.get(e['to'], 0) + 1",
" ent_rows = []",
" for i, n in enumerate(ix.g['nodes']):",
" p = n.get('props') or {}",
" desc = ' / '.join(str(p[k]) for k in ('definition', 'outline', 'comment', 'logicalName', 'rule') if p.get(k))",
" ent_rows.append({'id': n['id'], 'human_readable_id': i, 'title': n['label'], 'type': n['type'], 'description': desc or n['label'], 'text_unit_ids': ix.units_of.get(n['id'], []),",
" 'frequency': len(ix.units_of.get(n['id'], [])), 'degree': degree.get(n['id'], 0), 'x': 0.0, 'y': 0.0})",
" rel_rows = []",
" for e in ix.g['edges']:",
" tus = sorted(set(ix.units_of.get(e['from'], [])) & set(ix.units_of.get(e['to'], [])))",
" rel_rows.append({'id': 'edge:' + str(e['_i']), 'human_readable_id': e['_i'], 'source': e['from'], 'target': e['to'],",
" 'description': ix.nodes[e['from']]['label'] + ' ' + e['type'] + ' ' + ix.nodes[e['to']]['label'] + (' (inferred: ' + e['rule'] + ')' if e.get('inferred') else ''),",
" 'weight': 1.0, 'combined_degree': degree.get(e['from'], 0) + degree.get(e['to'], 0), 'text_unit_ids': tus})",
" key_to_comm = {c['key']: c['community'] for c in comms}",
" com_rows, rep_rows = [], []",
" for c in comms:",
" com_rows.append({'id': c['key'], 'human_readable_id': c['community'], 'community': c['community'], 'level': c['level'], 'parent': key_to_comm.get(c['parent'], -1),",
" 'children': [key_to_comm[k] for k in c['children'] if k in key_to_comm], 'title': c['title'], 'entity_ids': c['members'],",
" 'relationship_ids': ['edge:' + str(i) for i in c['relationships']], 'text_unit_ids': c['text_units'], 'period': today, 'size': c['size']})",
" r = reports.get(c['key'])",
" if r:",
" full = '# ' + r['title'] + '\\n\\n' + r['summary'] + '\\n\\n' + '\\n\\n'.join('## ' + f.get('summary', '') + '\\n\\n' + f.get('explanation', '') for f in r.get('findings', []))",
" rep_rows.append({'id': c['key'], 'human_readable_id': c['community'], 'community': c['community'], 'level': c['level'], 'parent': key_to_comm.get(c['parent'], -1),",
" 'children': [key_to_comm[k] for k in c['children'] if k in key_to_comm], 'title': r['title'], 'summary': r['summary'], 'full_content': full,",
" 'rank': float(r.get('rating') or 0), 'rating_explanation': r.get('rating_explanation', ''), 'findings': r.get('findings', []),",
" 'full_content_json': json.dumps(r, ensure_ascii=False), 'period': today, 'size': c['size']})",
" tu_rows, docs = [], {}",
" for i, u in enumerate(ix.units):",
" docs.setdefault(u['doc'], []).append(u['id'])",
" rel_ids = ['edge:' + str(e['_i']) for ent in u.get('entities') or [] for e in ix.out.get(ent, []) if e['to'] in set(u.get('entities') or [])]",
" tu_rows.append({'id': u['id'], 'human_readable_id': i, 'text': (u.get('heading') + '\\n' if u.get('heading') else '') + u['text'], 'n_tokens': max(1, len(u['text']) // 2),",
" 'document_ids': [u['doc']], 'entity_ids': u.get('entities') or [], 'relationship_ids': sorted(set(rel_ids)), 'covariate_ids': []})",
" doc_rows = [{'id': d, 'human_readable_id': i, 'title': d, 'text': '', 'text_unit_ids': ids, 'creation_date': today, 'metadata': None} for i, (d, ids) in enumerate(sorted(docs.items()))] # 空の struct は parquet に書けない",
" written = []",
" written.append(write_table(os.path.join(out_dir, 'entities'), ent_rows, ['id', 'human_readable_id', 'title', 'type', 'description', 'text_unit_ids', 'frequency', 'degree', 'x', 'y']))",
" written.append(write_table(os.path.join(out_dir, 'relationships'), rel_rows, ['id', 'human_readable_id', 'source', 'target', 'description', 'weight', 'combined_degree', 'text_unit_ids']))",
" written.append(write_table(os.path.join(out_dir, 'communities'), com_rows, ['id', 'human_readable_id', 'community', 'level', 'parent', 'children', 'title', 'entity_ids', 'relationship_ids', 'text_unit_ids', 'period', 'size']))",
" written.append(write_table(os.path.join(out_dir, 'community_reports'), rep_rows, ['id', 'human_readable_id', 'community', 'level', 'parent', 'children', 'title', 'summary', 'full_content', 'rank', 'rating_explanation', 'findings', 'full_content_json', 'period', 'size']))",
" written.append(write_table(os.path.join(out_dir, 'text_units'), tu_rows, ['id', 'human_readable_id', 'text', 'n_tokens', 'document_ids', 'entity_ids', 'relationship_ids', 'covariate_ids']))",
" written.append(write_table(os.path.join(out_dir, 'documents'), doc_rows, ['id', 'human_readable_id', 'title', 'text', 'text_unit_ids', 'creation_date', 'metadata']))",
" return written",
"",
"",
"def main():",
" ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)",
" ap.add_argument('root', nargs='?', default=os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), help='design document folder (parent of meta/)')",
" ap.add_argument('--out', default=os.path.join('meta', 'graphrag'), help='output folder relative to root (default meta/graphrag)')",
" ap.add_argument('--summarize', action='store_true', help='write community summaries with an LLM (ANTHROPIC_API_KEY / OPENAI_API_KEY)')",
" ap.add_argument('--provider', default='anthropic' if os.environ.get('ANTHROPIC_API_KEY') or not os.environ.get('OPENAI_API_KEY') else 'openai', choices=['anthropic', 'openai'])",
" ap.add_argument('--model', default=None)",
" ap.add_argument('--max', type=int, default=0, help='summarize at most N communities (0 = all)')",
" ap.add_argument('--level', type=int, default=None, help='summarize communities up to this level (0 = top only)')",
" ap.add_argument('--force', action='store_true', help='rewrite existing summaries')",
" ap.add_argument('--msgraphrag', default=None, metavar='DIR', help='export Microsoft GraphRAG index tables into DIR')",
" args = ap.parse_args()",
" root = os.path.abspath(args.root)",
" g, units = load(root)",
" ix = Index(g, units)",
" comms = build_communities(ix, g.get('lang', 'ja'))",
" os.makedirs(os.path.join(root, args.out), exist_ok=True)",
" cpath = os.path.join(root, args.out, 'communities.json')",
" json.dump({'schema': 'commonweal-communities/1', 'lang': g.get('lang'), 'counts': {'communities': len(comms), 'levels': max([c['level'] for c in comms] + [0]) + 1},",
" 'communities': [{k: v for k, v in c.items()} for c in comms]}, open(cpath, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)",
" print('communities: %d (levels %d) → %s' % (len(comms), max([c['level'] for c in comms] + [0]) + 1, cpath))",
" reports = {}",
" rpath = os.path.join(root, args.out, 'community_reports.json')",
" if args.summarize:",
" reports = summarize(root, ix, comms, args)",
" elif os.path.exists(rpath):",
" reports = {r['key']: r for r in json.load(open(rpath, encoding='utf-8')).get('reports', [])}",
" if args.msgraphrag:",
" for w in export_msgraphrag(ix, comms, reports, os.path.abspath(args.msgraphrag), g.get('lang', 'ja')):",
" print(' wrote ' + w)",
" return 0",
"",
"",
"if __name__ == '__main__':",
" sys.exit(main())",
].join('\n');
// [[MCP-SERVER-END]]
TFC.graphRagFiles = function () { // ★GraphRAG の静的ファイル (正本 src/common/graphrag/)
if (!_GRAPHRAG_README_MD) return [];
return [ { name: 'meta/graphrag/README.md', content: _GRAPHRAG_README_MD + '\n' }, { name: 'meta/graphrag/llamaindex_example.py', content: _GRAPHRAG_LLAMAINDEX_PY + '\n' },
{ name: 'meta/graphrag/communities.py', content: _GRAPHRAG_COMMUNITIES_PY + '\n' } ];
};
// graph-data.js (file:// では fetch が使えないので JS に包む。 U+2028 / U+2029 は古いエンジンで文字列リテラルを壊すのでエスケープ)
TFC.graphDataJs = function (graphJsonText, ontologyJsonText) {
var fix = function (t) { return String(t || 'null').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029'); };
return 'window.CW_GRAPH=' + fix(graphJsonText) + ';\nwindow.CW_ONTOLOGY=' + fix(ontologyJsonText) + ';\n';
};
// 他形式 → .a5er の変換は TFE (Ver1.0.7 に分離)。 入口 = EDM メンテナンスの直接アップロード (TFC.ensureEdmModels) と回帰テスト。
// ブラウザ完結の独立ページ (EDM 変換ツール、 Ver1.0.5〜1.0.6) は廃止 (Ver1.0.7、 直接アップロードに統合)
TFC.edmConvToA5er = function (text, opts) { return _tfe().edmConvToA5er(text, opts); };
// 以前の SETUP が置いた {サーバ側出力ベース}/tools/edm-converter.html を消す (SETUP から呼ぶ。 無ければ何もしない)
TFC.removeEdmConverterPage = function () {
var res = { removed: false, path: '' };
var cfg;
try { cfg = TFC.serverOutConfig(); } catch (e) { return res; }
if (!cfg.basePath) return res;
var Files = Java.type('java.nio.file.Files');
var Paths = Java.type('java.nio.file.Paths');
var file = Paths.get(cfg.basePath.replace(/[\\/]+$/, ''), 'tools', 'edm-converter.html');
res.path = String(file);
try { res.removed = !!Files.deleteIfExists(file); } catch (e2) {}
return res;
};
// 既知プロジェクトトークン (昇順・重複なし)。
// 汎用CD TLN_FUNC_DOC_PROJECT の KEY_CODE (= 画面のチェックボックスが出す値) に加え、
// EDM / 辞書に実際に格納されている値も拾う (汎用CD から消された後も残る値の救済)。
TFC.knownProjectTokens = function (sep) {
var s = sep || TFC.checkboxSep();
var seen = {}, out = [];
function add(raw) {
var toks = _tfcSplitProjectIds(raw, s);
for (var i = 0; i < toks.length; i++) {
if (!seen[toks[i]]) { seen[toks[i]] = 1; out.push(toks[i]); }
}
}
try {
var hc = TFC.selectPS(
'SELECT KEY_CODE FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ?',
['TLN_FUNC_DOC_PROJECT']);
for (var h = 0; h < hc.length; h++) add(hc[h]['KEY_CODE']);
} catch (eH) { /* 汎用CD 未投入 = 拾えるものだけ */ }
var srcs = [{ t: 'TLN_M_FUNC_EDM', c: 'PROJECT_ID' },
{ t: 'TLN_M_FUNC_DOMAIN', c: 'PROJECT_ID' }];
for (var si = 0; si < srcs.length; si++) {
try {
if (TFC.tableColumns(srcs[si].t).indexOf(srcs[si].c) < 0) continue;
var rs = TFC.selectPS('SELECT DISTINCT ' + srcs[si].c + ' AS PJ FROM ' + srcs[si].t, []);
for (var r2 = 0; r2 < rs.length; r2++) add(rs[r2]['PJ']);
} catch (eS) { /* 列が無い旧 DB / 権限なし = スキップ */ }
}
out.sort();
return out;
};
/**
* 可視プロジェクト索引 ('P' 行) を作り直す。
* @param {boolean} force true = 署名が同じでも必ず作り直す (カタログ洗い替え直後)
* @param {boolean} commit true = 書込み後に明示 commit する。
* ★検索前JS (0R100) はトランザクション外で走り、 検索の終了時に
* rollback されるため 明示 commit しないと索引が残らない
* (宿題一覧の TFC.rebuildDomainTasksWkFromCatalog と同じ作法)。
* 確定処理 (0S101 = EDM 確定) から呼ぶときは TALON の
* トランザクション管理に任せる = commit しない。
* @returns {rows: 作った属性行数, skipped: 署名一致でスキップしたか}
*/
TFC.rebuildEdmAttrPjRows = function (force, commit) {
var res = { rows: 0, skipped: false };
// PJ_LIST は Ver0.61 追加列 — セットアップ未実行の旧 DB では列が無い
try {
if (TFC.tableColumns(EDM_ATTR_WK).indexOf('PJ_LIST') < 0) {
res.skipped = true;
return res;
}
} catch (eTc2) { res.skipped = true; return res; }
var sep = TFC.checkboxSep();
var known = TFC.knownProjectTokens(sep);
var sigFull = known.join(sep);
var sig = (sigFull.length > EDM_CAT_PJLIST_MAX)
? sigFull.substring(0, EDM_CAT_PJLIST_MAX) : sigFull;
if (!force) {
try {
var cur = TFC.selectPS(
'SELECT PJ_LIST FROM ' + EDM_ATTR_WK +
" WHERE EDM_CD = ? AND ROW_KBN = 'P' AND SEQ_NO = 0", [EDM_CAT_PJ_CD]);
if (cur.length > 0 && TFC.s(cur[0]['PJ_LIST']) === sig) {
res.skipped = true;
return res;
}
} catch (eSg) { /* 署名が読めない = 作り直す */ }
}
var attrRows = TFC.selectPS(
'SELECT ATTR_NM, PROJECT_ID FROM ' + EDM_ATTR_WK + " WHERE ROW_KBN = 'A'", []);
var rows = _tfcEdmAttrPjRows(attrRows, known, sep);
TFC.updatePS('DELETE FROM ' + EDM_ATTR_WK + " WHERE ROW_KBN = 'P'", []);
var INS_P = 'INSERT INTO ' + EDM_ATTR_WK +
' (EDM_CD, ROW_KBN, SEQ_NO, EDM_NM, PROJECT_ID, ENTITY_NM, ENTITY_CD,' +
' ATTR_NM, ATTR_CD, DOMAIN_NM, QUALIFIED_NM, PJ_LIST)' +
' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
function insP(seqNo, attrNm, pjList) {
try {
TFC.updatePS(INS_P, [EDM_CAT_PJ_CD, 'P', _JInt.valueOf(seqNo), '', null, '', '', // No.285: PROJECT_ID は NULL
attrNm, '', '', '', pjList]);
return true;
} catch (eIp) {
if (!/DOMA2004|unique|constraint|重複|PRIMARY|duplicate/i.test(String(eIp))) throw eIp;
return false;
}
}
// SEQ_NO=0 = 署名行 (ATTR_NM 空 = 子画面の LIKE '_%' で候補に出ない)
insP(0, '', sig);
// 列幅を超えるときは **区切りの手前で** 切る (トークンを途中で割ると
// 別プロジェクトに化ける危険があるため。 落ちたプロジェクトからは
// その候補が見えなくなるので警告も出す)
function cutTokens(list) {
if (list.length <= EDM_CAT_PJLIST_MAX) return list;
var cutAt = list.lastIndexOf(sep, EDM_CAT_PJLIST_MAX);
return (cutAt > 0) ? list.substring(0, cutAt) : '';
}
var truncated = 0;
for (var i = 0; i < rows.length; i++) {
var pjl = rows[i].pjList;
if (pjl.length > EDM_CAT_PJLIST_MAX) {
pjl = cutTokens(pjl);
truncated++;
}
if (insP(i + 1, _edmCatCut(rows[i].attrNm, EDM_CAT_NM_MAX), pjl)) res.rows++;
}
if (truncated > 0) {
try {
TALON.getLogger().writeWarn('[TFC-EDM-CATALOG] 可視プロジェクト列が ' +
EDM_CAT_PJLIST_MAX + ' 文字を超えたため切り詰めました (' + truncated +
' 行)。 プロジェクト数が多すぎる可能性があります');
} catch (igT) {}
}
if (commit) {
try { TalonDbUtil.commit(TALON.getDbConfig()); } catch (eCm) {}
}
return res;
};
// 登録済み EDM の属性カタログ (エンティティ×属性名) を取得する。
// メンテ画面の入力補助 (EDM 属性宣言の存在チェック + 候補提示) 用。
// Ver0.53: .a5er の直接パースをやめ、 カタログ WK を読む
// (ファイルを読むのは TFC.rebuildEdmAttrWk = EDM 確定時 / SETUP 実行時だけ)。
// 戻り値: { hasData: bool, entities: [{ nm, cd, attrs: [属性名,...],
// attrDoms: [ドメイン欄の値,...] }] }
// attrDoms は attrs と同じ添字で対応する 型欄 (A5M2 ドメイン列) の値。
// Ver0.55: 宣言先が別のデータドメインに解決される場合の警告で使う
// (既存の呼出は attrs だけを見るため後方互換)。
// EDM 未登録 / カタログ未作成 (SETUP 未実行) → hasData=false (検証はスキップ)
TFC.listEdmAttrCatalog = function () {
var res = { hasData: false, entities: [] };
try {
var rows = TFC.selectPS(
'SELECT EDM_CD, PROJECT_ID, ENTITY_NM, ENTITY_CD, ATTR_NM, DOMAIN_NM FROM ' + EDM_ATTR_WK +
" WHERE ROW_KBN = 'A' ORDER BY EDM_CD, SEQ_NO", []);
var cur = null, curEdm = null, curNm = null, curCd = null;
for (var i = 0; i < rows.length; i++) {
var entCd = TFC.s(rows[i]['ENTITY_CD']);
// 論理名 (LName) 未設定なら物理名 (PName) へフォールバック —
// 出力側レジストリ (_loadEdmRegistry の nm = lname || pname) と同一規則。
// ここで捨てると「設計書では解決されるのに確定時検証だけ迷子警告」の
// 非整合になる (2026-08-24 整合監査で検出)
var entNm = TFC.s(rows[i]['ENTITY_NM']) || entCd;
if (!entNm) continue; // 論理名も物理名も無いエンティティのみ除外
var edmCd = TFC.s(rows[i]['EDM_CD']);
// カタログは EDM 内の出現順 (SEQ_NO) で並ぶので 連続する同一エンティティをまとめる
if (cur == null || edmCd !== curEdm || entNm !== curNm || entCd !== curCd) {
cur = { nm: entNm, cd: entCd, attrs: [], attrDoms: [], projects: TFC.splitProjectIds(rows[i]['PROJECT_ID']) }; /* ★No.270: EDM のプロジェクト (空 = 共通) */
res.entities.push(cur);
curEdm = edmCd; curNm = entNm; curCd = entCd;
}
var attrNm = TFC.s(rows[i]['ATTR_NM']);
if (attrNm) {
cur.attrs.push(attrNm);
cur.attrDoms.push(TFC.s(rows[i]['DOMAIN_NM']));
}
}
res.hasData = res.entities.length > 0;
} catch (e) {
try { TALON.getLogger().writeInfo('[TFC] EDM 属性カタログ取得スキップ: ' + e); } catch (ig) {}
}
return res;
};
// ============================================================
// プロジェクト (コンテキスト) 集合の比較 (Ver0.57)
// PROJECT_ID は TALON チェックボックス複数値 (区切り文字連結 "A;B") で持つ。
// ★意味論: 空 (未選択) = 「全プロジェクトと重なる」(共通)。 設計書出力の
// _projectVisible (行側が空なら常に可視) と同じ扱いで、 出力時に必ず同居する。
// 純関数なので Node 単体回帰の対象 (tests/test_domain_name_dup.py)。
// ============================================================
// 区切り文字連結の PROJECT_ID をトークン配列へ分解する。
// 区切り文字 (既定 ';') に加えて カンマ / 角括弧 / 空白 も区切りとみなす
// (REST や画面から配列表現 "[A, B]" で届くことがあるため)。
function _tfcSplitProjectIds(raw, sep) {
var out = [];
var s = (raw == null) ? '' : String(raw);
if (!s) return out;
var esc = String(sep || ';').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
var parts = s.split(new RegExp('[' + esc + ',\\[\\]\\s]+'));
for (var i = 0; i < parts.length; i++) {
if (parts[i]) out.push(parts[i]);
}
return out;
}
// ★No.262 (Ver1.0.22): データドメイン名称の同名判定のキー = 前後の空白 (全角含む) を除き、 全角 / 半角を同一視 (NFKC 互換正規化: 全角英数字・記号 → 半角、
// 半角カナ → 全角カナ、 ㈱ → (株) 等) し、 大文字小文字を同一視。 SQL Server / MySQL の照合 (幅・大小文字を区別しない) と Oracle / PostgreSQL (バイト比較) で
// 成否が分かれないよう、 比較は SQL ではなく JS で行う (呼び手 = TFC.checkDomainNameDup / 業務データ辞書CSV一括登録のファイル内重複)。
// 正規化は String.prototype.normalize (Node / ブラウザ) → java.text.Normalizer (Nashorn) → 全角 ASCII だけの簡易変換 の順で試す
function _tfcDomainNameKey(nm) {
var s = (nm == null) ? '' : String(nm);
s = s.replace(/^[\s\u3000]+|[\s\u3000]+$/g, '');
if (!s) return '';
var done = false;
try { if (typeof s.normalize === 'function') { s = s.normalize('NFKC'); done = true; } } catch (e1) {}
if (!done) {
try { var NZ = Java.type('java.text.Normalizer'), NF = Java.type('java.text.Normalizer$Form'); s = String(NZ.normalize(s, NF.NFKC)); done = true; } catch (e2) {}
}
if (!done) {
s = s.replace(/[\uFF01-\uFF5E]/g, function (c) { return String.fromCharCode(c.charCodeAt(0) - 0xFEE0); });
}
return s.toUpperCase();
}
TFC.domainNameKey = _tfcDomainNameKey;
// プロジェクト集合が重なるか (= 同じ出力に同居し得るか)。
// どちらかが空 (共通) → true / 共通要素あり → true / それ以外 (素) → false
function _tfcProjectsOverlap(aList, bList) {
var a = aList || [], b = bList || [];
if (a.length === 0 || b.length === 0) return true;
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < b.length; j++) {
if (a[i] === b[j]) return true;
}
}
return false;
}
TFC.splitProjectIds = _tfcSplitProjectIds;
TFC.projectsOverlap = _tfcProjectsOverlap;
// 同名エントリ群を「自分と同じ出力に同居し得るか」で 2 分する (★純関数)。
// overlapping = 同居する (= 本当に困る) / disjoint = 同居しない (= 参考情報)
// 物理属性ヒット行 (DOMAIN_CD / ATTR_NM / MAIN_NM / PROJECT_ID) を DOMAIN_CD 単位へ畳む。
// ★純関数 (DB 非依存 — tests/test_domain_name_dup.py が Node で直接評価する)。
// 同じドメインに表記ゆれの同名物理属性が複数行あっても 1 エントリにまとめ、
// 一致した ATTR_NM は 大文字化した値で一意化して昇順に持つ。
// 並びは DOMAIN_CD 昇順 (DB の行順は非決定 — メッセージを決定的にするため)。
// TALON チェックボックス複数値の区切り文字 (汎用CD TLN_GENERAL/CHECKBOX_SEP、 既定 ';')
TFC.checkboxSep = function () {
var sep = ';';
try {
var rows = TFC.selectPS(
'SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ? AND KEY_CODE = ?',
['TLN_GENERAL', 'CHECKBOX_SEP']);
if (rows.length > 0 && TFC.s(rows[0]['DSP1'])) sep = TFC.s(rows[0]['DSP1']);
} catch (e) { /* 既定 ';' のまま */ }
return sep;
};
// プロジェクトID → 表示名 (汎用CD TLN_FUNC_DOC_PROJECT の DSP1)。 未登録キーはそのまま返す
TFC.projectLabelMap = function () {
var map = {};
try {
var rows = TFC.selectPS(
'SELECT KEY_CODE, DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ?',
['TLN_FUNC_DOC_PROJECT']);
for (var i = 0; i < rows.length; i++) {
var k = TFC.s(rows[i]['KEY_CODE']);
var v = TFC.s(rows[i]['DSP1']);
if (k) map[k] = v || k;
}
} catch (e) { /* 汎用CD 未投入 = キー表示 */ }
return map;
};
// ============================================================
// データドメイン名称 (MAIN_NM) の同名チェック
// ★テスター指摘 No.131 (Ver0.56) = 同名は確定をブロック。
// ★Ver0.57 = 「プロジェクト集合の重なり」で 2 分する:
// ・どちらかがプロジェクト未設定 (= 全プロジェクトと重なる) → ブロック
// ・共通のプロジェクトがある → ブロック
// ・両方が非空で共通なし (素) → 登録可 + 警告
// 名前解決 (物理項目・EDM 属性 → データドメイン) は同じ出力の中で 1 件に
// 決まればよいので、 出力時に同居し得ない同名は許してよい (ユーザー決定)。
// 正規化は辞書の名前解決 (byMainNm) と同じ「前後空白除去 + 大文字化の完全一致」。
// 集合比較は SQL ではなく JS 側で行う (DB 方言に依存させない)。
//
// 引数: mainNm=入力した名称 / domainCd=自分自身 (更新時。 空 = 新規) /
// selfProjectRaw=自分の PROJECT_ID (区切り文字連結。 空 = 未設定)
// 戻り値: { key, selfProjects, blocking: [entry...], disjoint: [entry...] }
// entry = { domainCd, mainNm, projects: [ID...], projectNames: [表示名...] }
// 並びは DOMAIN_CD 昇順 (メッセージを決定的にするため)
// ============================================================
TFC.checkDomainNameDup = function (mainNm, domainCd, selfProjectRaw) {
var out = { key: '', selfProjects: [], blocking: [], disjoint: [] };
var key = _tfcDomainNameKey(mainNm); // ★No.262: 全角 / 半角・大小文字・前後の空白を同一視 (DB の照合に依らず JS で比べる)
out.key = key;
if (!key) return out;
// PROJECT_ID は v0.15 追加列 — SETUP 未実行の旧 DB では列が無いため先に検出する
// (列なし = 全員がプロジェクト未設定 = 従来どおり全同名をブロック)
var hasPj = false;
try { hasPj = TFC.tableColumns('TLN_M_FUNC_DOMAIN').indexOf('PROJECT_ID') >= 0; } catch (eTc) {}
// ★No.262: SQL の UPPER(LTRIM(RTRIM(MAIN_NM))) = ? は DB の照合に左右される (SQL Server / MySQL は全角 / 半角を同一視、 Oracle / PostgreSQL は区別し、
// 同じ名前の登録が DB によって通ったり通らなかったりした) ので、 候補を全部読んで JS の同じキー (_tfcDomainNameKey) で比べる (辞書は高々数千行)
var sql = 'SELECT DOMAIN_CD, MAIN_NM' + (hasPj ? ', PROJECT_ID' : '') + ' FROM TLN_M_FUNC_DOMAIN';
var prm = [];
if (domainCd) { sql += ' WHERE DOMAIN_CD <> ?'; prm.push(domainCd); }
var all = TFC.selectPS(sql, prm), rows = [];
for (var ai = 0; ai < all.length; ai++) if (_tfcDomainNameKey(all[ai]['MAIN_NM']) === key) rows.push(all[ai]);
if (rows.length === 0) return out;
var sep = TFC.checkboxSep();
var labels = TFC.projectLabelMap();
out.selfProjects = _tfcSplitProjectIds(hasPj ? selfProjectRaw : '', sep);
var seen = {}, list = [];
for (var i = 0; i < rows.length; i++) {
var cd = TFC.s(rows[i]['DOMAIN_CD']);
if (!cd || seen[cd]) continue;
seen[cd] = true;
var pj = _tfcSplitProjectIds(hasPj ? rows[i]['PROJECT_ID'] : '', sep);
var pjNm = [];
for (var p = 0; p < pj.length; p++) pjNm.push(labels[pj[p]] || pj[p]);
list.push({ domainCd: cd, mainNm: TFC.s(rows[i]['MAIN_NM']),
projects: pj, projectNames: pjNm });
}
// ★決定的順序 (DB の行順は非決定 — メッセージが揺れないよう DOMAIN_CD 昇順)
list.sort(function (a, b) {
return a.domainCd < b.domainCd ? -1 : (a.domainCd > b.domainCd ? 1 : 0);
});
for (var j = 0; j < list.length; j++) {
if (_tfcProjectsOverlap(out.selfProjects, list[j].projects)) out.blocking.push(list[j]);
else out.disjoint.push(list[j]);
}
return out;
};
// 同名チェックの相手側ラベル (「名称 [コード] (プロジェクト)」) を作る
TFC.domainDupLabels = function (list, lang) {
var EN = (lang === 'en');
var out = [];
for (var i = 0; i < (list || []).length; i++) {
var e = list[i];
var pj = e.projectNames && e.projectNames.length
? e.projectNames.join(EN ? ', ' : '・')
: TFC.t('dom.dupMainNm.noProj', lang);
out.push(e.mainNm + ' [' + e.domainCd + ']' +
(EN ? ' (' + pj + ')' : '(' + pj + ')'));
}
return out;
};
// ============================================================
// 採番 (Ver1.0.11): TALON 標準の採番と同じ TLN_M_SEQ (LINE_NO) / TLN_M_SEQ_PARAMETER (KIND 1=固定値 / 3=連番桁数) で次の値を作る。
// EDM属性割当の確定 JS がデータドメイン (TLN_FUNC_DOC_DOMAIN_KEY = 'D' + 12 桁) と 属性行の SEQ_NO (TLN_FUNC_DOC_DOMAIN_ATTR_SEQ) を
// 画面項目の採番を通さずに作るため。 同じ行を UPDATE で進めるので TALON 側の採番と重ならない (行ロックはトランザクション終了まで)。
// 戻り値: 文字列 (固定値 + 連番) / 連番だけの定義なら数字文字列。 定義が無ければ例外
// ============================================================
TFC.nextSaibanCode = function (sikibetuCode) {
var params = TFC.selectPS('SELECT SEQ_NO, KIND, VALUE FROM TLN_M_SEQ_PARAMETER WHERE SAIBAN_SIKIBETU_CODE = ? ORDER BY SEQ_NO', [sikibetuCode]);
if (params.length === 0) throw new Error('TLN_M_SEQ_PARAMETER: ' + sikibetuCode + ' が定義されていません');
var now = new (Java.type('java.sql.Timestamp'))(Java.type('java.lang.System').currentTimeMillis());
var n = TFC.updatePS('UPDATE TLN_M_SEQ SET LINE_NO = LINE_NO + 1, UPDATED_DATE = ?, MODIFY_COUNT = MODIFY_COUNT + 1 ' +
"WHERE SAIBAN_SIKIBETU_CODE = ? AND BREAK_KEY = 'NONE'", [now, sikibetuCode]);
if (!n) {
TFC.updatePS('INSERT INTO TLN_M_SEQ (SAIBAN_SIKIBETU_CODE, BREAK_KEY, LINE_NO, CREATED_DATE, UPDATED_DATE, MODIFY_COUNT) ' +
"VALUES (?, 'NONE', 1, ?, ?, 0)", [sikibetuCode, now, now]);
}
var rows = TFC.selectPS("SELECT LINE_NO FROM TLN_M_SEQ WHERE SAIBAN_SIKIBETU_CODE = ? AND BREAK_KEY = 'NONE'", [sikibetuCode]);
var lineNo = rows.length ? Number(rows[0]['LINE_NO']) : 1;
var out = '';
for (var i = 0; i < params.length; i++) {
var kind = TFC.s(params[i]['KIND']), val = TFC.s(params[i]['VALUE']);
if (kind === '1') out += val; // 固定値
else if (kind === '3') { // 連番桁数 (ゼロ埋め)
var digits = parseInt(val, 10) || 0, num = String(lineNo);
while (num.length < digits) num = '0' + num;
out += num;
}
}
return out;
};
var UI_LANG_SIKIBETU = 'TLN_FUNC_DOC_LANGUAGE';
// 環境の画面言語 ('ja'|'en')。 マーカー汎用CD があればそれを優先し、
// 無ければ従来どおり利用者のブラウザ言語 (detectLang)。
// 画面に固定表示される値 (グリッドの状態値など) はこちらを使う。
// メッセージ (addMsg 等) は TALON 標準メッセージと同じ挙動に揃えるため
// 従来どおり TFC.detectLang() を使うこと。
TFC.uiLang = function () {
try {
var rows = TFC.selectPS(
'SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ? AND KEY_CODE = ?',
[UI_LANG_SIKIBETU, 'LANG']);
if (rows.length > 0) {
var v = String(rows[0]['DSP1'] || '').toLowerCase();
if (v === 'en' || v === 'ja') return v;
}
} catch (e) { /* マーカー未整備なら detectLang へ */ }
return TFC.detectLang();
};
// CLOB → 文字列 (BODY_SQL の全長読出。 §5.2 と同じ getSubString パターン)
function _uiLangClobToStr(v) {
if (v == null) return '';
try {
if (typeof v.getSubString === 'function') {
return String(v.getSubString(1, v.length()));
}
} catch (e) { /* fall through */ }
return String(v);
}
/**
* 製品画面の表示文言を toLang ('ja'|'en') へ書き換える。
* @returns {updated: 書換行数, skipped: 値不一致でスキップしたキー数, total: 対象キー数}
*/
TFC.changeUiLanguage = function (toLang) {
if (toLang !== 'ja' && toLang !== 'en') {
throw 'changeUiLanguage: invalid language ' + toLang;
}
var toIdx = (toLang === 'en') ? 1 : 0;
var fromIdx = 1 - toIdx;
var updated = 0, skipped = 0, total = 0;
function upd(sql, params) {
total++;
var n = TFC.updatePS(sql, params);
if (n > 0) { updated += n; } else { skipped++; }
}
var k, pair, parts;
for (k in UI_LANG.FUNC_NM) {
pair = UI_LANG.FUNC_NM[k];
upd('UPDATE TLN_M_GENERAL_FUNC SET FUNC_NM = ? WHERE FUNC_ID = ? AND FUNC_NM = ?',
[pair[toIdx], k, pair[fromIdx]]);
}
for (k in UI_LANG.TITLE) {
pair = UI_LANG.TITLE[k]; parts = k.split('|');
upd('UPDATE TLN_M_GENERAL_FUNC_SQL SET TITLE = ? ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND TITLE = ?',
[pair[toIdx], parts[0], Number(parts[1]), pair[fromIdx]]);
}
for (k in UI_LANG.DISP_NAME) {
pair = UI_LANG.DISP_NAME[k]; parts = k.split('|');
// ★COL_NAME は UPPER() で突合する。 PG 系環境では SETUP が col_name を
// 小文字化するため、 大文字キーの完全一致だと全件スキップになる
// (pg 納品環境で updated 60/188 になった実測バグの修正)
// ★DISP_NAME は前後空白を除去して突合する (No.119: デザイナ入力由来の
// 末尾スペース ('業務的定義 ') で値ガードが外れ変換されなかった。
// 書込値はクリーンな対訳なので、変換を通すと空白も正規化される)
upd('UPDATE TLN_M_GENERAL_ITEM SET DISP_NAME = ? ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND UPPER(COL_NAME) = ? ' +
'AND LTRIM(RTRIM(DISP_NAME)) = ?',
[pair[toIdx], parts[0], Number(parts[1]), parts[2], pair[fromIdx]]);
}
// 項目グループ名 (No.119: グループ見出しの変換漏れ)。 ラベル単位で製品全機能へ適用
for (k in UI_LANG.GROUP_NAME) {
pair = UI_LANG.GROUP_NAME[k];
upd("UPDATE TLN_M_GENERAL_ITEM SET GROUP_NAME = ? " +
"WHERE FUNC_ID LIKE 'TLN_FUNC_DOC%' AND LTRIM(RTRIM(GROUP_NAME)) = ?",
[pair[toIdx], pair[fromIdx]]);
}
for (k in UI_LANG.APP_VALUE) {
pair = UI_LANG.APP_VALUE[k]; parts = k.split('|');
upd('UPDATE TLN_M_GENERAL_APP SET VALUE = ? ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND FUNC_KBN = ? AND VALUE = ?',
[pair[toIdx], parts[0], Number(parts[1]), parts[2], pair[fromIdx]]);
}
for (k in UI_LANG.BTN_KIND) {
pair = UI_LANG.BTN_KIND[k];
upd("UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = ? " +
"WHERE FUNC_ID LIKE 'TLN_FUNC_DOC%' AND FUNC_KBN LIKE 'BUTTON%' AND KIND = ?",
[pair[toIdx], pair[fromIdx]]);
}
for (k in UI_LANG.USES_LABEL) {
pair = UI_LANG.USES_LABEL[k];
// ★OPTN='BUTTON' (利用者定義の行ボタン) のみ。 VIEW/COPY/DELETE は
// TALON 標準ラベルで デザイナが再生成するため対象外 (UI_LANG 参照)
upd("UPDATE TLN_M_GENERAL_USES SET KEY_CODE = ? " +
"WHERE FUNC_ID LIKE 'TLN_FUNC_DOC%' AND FUNC_KBN = 'LIST' " +
"AND OPTN = 'BUTTON' AND KEY_CODE = ?",
[pair[toIdx], pair[fromIdx]]);
}
for (k in UI_LANG.HANYO_DSP1) {
pair = UI_LANG.HANYO_DSP1[k]; parts = k.split('|');
upd('UPDATE TLN_M_HANYO_CODE_MAIN SET DSP1 = ? ' +
'WHERE SIKIBETU_CODE = ? AND KEY_CODE = ? AND DSP1 = ?',
[pair[toIdx], parts[0], parts[1], pair[fromIdx]]);
}
for (k in UI_LANG.CSV_BTN_LABEL) {
pair = UI_LANG.CSV_BTN_LABEL[k]; parts = k.split('|');
upd('UPDATE TLN_M_GENERAL_ITEM_OPTN SET COL_NAME = ? ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND FUNC_KBN = ? AND COL_NAME = ?',
[pair[toIdx], parts[0], Number(parts[1]), parts[2], pair[fromIdx]]);
}
// ★Ver1.0.22 (No.232): グラフの凡例 (系列の CHR_TEXT = CLOB → 読んで比べて主キーで更新) と単位 (CHR5)
for (k in UI_LANG.CHART_SERIES) {
pair = UI_LANG.CHART_SERIES[k]; parts = k.split('|');
var srows = TFC.selectPS('SELECT OPT_SORT, CHR_TEXT FROM TLN_M_GENERAL_ITEM_OPTN ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND COL_NAME = ? AND FUNC_KBN = ? AND CHR1 = ?',
[parts[0], Number(parts[1]), 'CHART_SERIES_BASE', 'CHART', parts[2]]);
for (var si = 0; si < srows.length; si++) {
total++;
if (_uiLangClobToStr(srows[si]['CHR_TEXT']) === pair[fromIdx]) {
updated += TFC.updatePS('UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR_TEXT = ? ' +
'WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND COL_NAME = ? AND FUNC_KBN = ? AND OPT_SORT = ?',
[pair[toIdx], parts[0], Number(parts[1]), 'CHART_SERIES_BASE', 'CHART', Number(srows[si]['OPT_SORT'])]);
} else {
skipped++;
}
}
}
for (k in UI_LANG.CHART_UNIT) {
pair = UI_LANG.CHART_UNIT[k]; parts = k.split('|');
upd('UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR5 = ? ' +
"WHERE FUNC_ID = ? AND FUNC_SEQ = ? AND COL_NAME = 'CHART_SERIES_BASE' AND FUNC_KBN = 'CHART' AND CHR5 = ?",
[pair[toIdx], parts[0], Number(parts[1]), pair[fromIdx]]);
}
// メニュー (TFC.registerMenu で登録した フォルダ名 / 表示名)。
// ★メニューは リポジトリ移送の対象外 = 取込で ja に戻らない。 en 運用環境で
// 取込後に [英語に変換] を押しても、 メニューは既に en のままなので
// 値ガードで空振り (skipped) する — 冪等なので実害はない
for (k in UI_LANG.MENU_GRP) {
pair = UI_LANG.MENU_GRP[k];
upd('UPDATE TLN_M_AUTHORITY SET FUNC_NM = ? WHERE FUNC_ATH_ID = ? AND FUNC_NM = ?',
[pair[toIdx], k, pair[fromIdx]]);
}
for (k in UI_LANG.MENU_NM) {
pair = UI_LANG.MENU_NM[k];
// フォルダは限定しない (利用者が別フォルダへ移していても表示名は追随させる)
upd('UPDATE TLN_M_FUNCTION SET FUNC_NM = ? WHERE FUNC_ID = ? AND FUNC_NM = ?',
[pair[toIdx], k, pair[fromIdx]]);
}
// 改訂履歴 3 画面 (Ver1.0.6: 「変更した列」の表示名) の BODY_SQL 内の表示リテラル。
// 引用符込みで置換して部分文字列の誤置換を防ぐ。 変更があった行だけ UPDATE。
var litFuncs = ['TLN_FUNC_DOC_DOMAIN_HISTORY', 'TLN_FUNC_DOC_DOMAIN_HISTORY_DETAIL', 'TLN_FUNC_DOC_EDM_HISTORY',
'TLN_FUNC_DOC_DOMAIN_TASKS']; // Ver1.0.18: 宿題一覧の 済/未
for (var lf = 0; lf < litFuncs.length; lf++) {
var bodies = TFC.selectPS(
'SELECT FUNC_SEQ, BODY_SQL FROM TLN_M_GENERAL_FUNC_SQL WHERE FUNC_ID = ?',
[litFuncs[lf]]);
for (var bi = 0; bi < bodies.length; bi++) {
var body = _uiLangClobToStr(bodies[bi]['BODY_SQL']);
if (!body) continue;
var newBody = body;
for (k in UI_LANG.SQL_LIT) {
pair = UI_LANG.SQL_LIT[k];
newBody = newBody.split("'" + pair[fromIdx] + "'").join("'" + pair[toIdx] + "'");
}
total++;
if (newBody !== body) {
updated += TFC.updatePS(
'UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = ? WHERE FUNC_ID = ? AND FUNC_SEQ = ?',
[newBody, litFuncs[lf], Number(bodies[bi]['FUNC_SEQ'])]);
} else {
skipped++;
}
}
}
// ★Ver1.0.22 (No.232): EDM 履歴の「変更内容」(CHANGE_NOTE) は版を記録した時点の環境言語で生成した文字列 = データ側に残る。
// 版の .a5er (HIS_SRC_FILE) は残っているので、 変換先の言語で前の版との差分を作り直す (ER ライブラリが無い等で失敗した行は残す)
try {
var regen = TFC.regenEdmHistoryNotes(toLang);
total += regen.total; updated += regen.updated; skipped += regen.skipped;
} catch (eRegen) {
try { TALON.getLogger().writeWarn('[TFC] EDM 履歴の変更内容の作り直しに失敗 (言語変換は続行): ' + eRegen); } catch (ig) {}
}
// 現在言語マーカー (無ければ作成)
var mk = TFC.selectPS(
'SELECT COUNT(*) CNT FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ? AND KEY_CODE = ?',
[UI_LANG_SIKIBETU, 'LANG']);
if (Number(mk[0]['CNT']) > 0) {
TFC.updatePS('UPDATE TLN_M_HANYO_CODE_MAIN SET DSP1 = ? WHERE SIKIBETU_CODE = ? AND KEY_CODE = ?',
[toLang, UI_LANG_SIKIBETU, 'LANG']);
} else {
TFC.updatePS('INSERT INTO TLN_M_HANYO_CODE_MAIN ' +
'(SIKIBETU_CODE, KEY_CODE, SIKIBETU_NM, DSP1, DSP_NO1, DSP_SORT1) ' +
'VALUES (?, ?, ?, ?, 0, 0)',
[UI_LANG_SIKIBETU, 'LANG', '設計書_画面言語', toLang]);
}
TALON.getLogger().writeInfo('[TFC] changeUiLanguage(' + toLang + '): updated=' + updated +
' skipped=' + skipped + ' total=' + total);
return { updated: updated, skipped: skipped, total: total };
};
// ================================================================
// メニュー登録 — セットアップ画面の [メニュー登録] (Ver0.54)
//
// TALON のメニューは リポジトリ移送の対象外 (機能設定・汎用CD・採番・JS のみが
// 運ばれる) のため、 取込だけでは製品の画面がメニューに出ない。 従来は
// セットアップガイド (Zendesk 記事4) §6「メニュー登録」を見ながら TALON 標準の
// メニュー設定機能で手登録してもらっていた。 これをボタン 1 つで済ませる。
//
// 触る 3 表 (いずれも TALON 標準):
// TLN_M_AUTHORITY メニューフォルダ (FUNC_ATH_ID, FUNC_NM)
// TLN_M_GROUP_RELATION ユーザグループ × フォルダ (FUNC_GRP_ID, FUNC_ATH_ID)
// TLN_M_FUNCTION フォルダ配下のメニュー項目 (FUNC_ATH_ID, FUNC_ID)
//
// 設計の約束:
// - **冪等**。 何度押しても増えない
// - **利用者の配置を尊重**する。 判定は「FUNC_ID が TLN_M_FUNCTION に
// 1 行でもあるか」(フォルダ横断) で行い、 有れば skip。 利用者が別フォルダへ
// 移した / 名前を変えた / 意図的に外した項目を作り直さない
// - **DELETE しない**。 撤去はセットアップガイド §10「アンインストール」の
// 手動 SQL に委ねる
// - 紐付け先のユーザグループは **実行権限 (TLN_M_GENERAL_AUTH) から動的導出**する
// (製品 CSV に同梱される実行権限と必ず一致させるため。 ハードコードしない)
// - PRINT_SORT は sortBase 起点。 既に使われている値は避けて空き窓へ退避する
// - 表示名は環境の現在言語 (TFC.uiLang) で入れる。 対訳は UI_LANG.MENU_NM が正本
// - **出荷名を改名したら 既存行も追随させる** (Ver0.62 / テスター指摘 No.137)。
// ただし追随させるのは **過去に出荷した名前と完全一致する行だけ**
// (MENU_NM_LEGACY の値ガード = changeUiLanguage と同じ思想)。 利用者が
// 独自に付けた名前は「利用者の配置を尊重する」約束どおり触らない
// - ★反映は **再ログイン後** (TALON のメニュー Bean が SessionScoped のため)
// ================================================================
// 過去に出荷した メニュー表示名 (FUNC_ID → [[ja, en], ...] 古い順)。
// registerMenu が「旧出荷名と完全一致する行」だけを現行の UI_LANG.MENU_NM へ
// 改名する。 ★改名するときは 旧値をここへ追記すること (消さない — 何世代前の
// 環境から更新されても追随できるようにするため)。
var MENU_NM_LEGACY = {
// Ver0.54〜0.61 の出荷名 (No.137 で機能名・マニュアル表記と統一)
'TLN_FUNC_DOC': [['設計情報出力', 'Design information output']],
'TLN_FUNC_DOC_EXCL_MAINTE': [['項目除外', 'Column exclusions']],
'TLN_FUNC_DOC_EXCL_PICK': [['項目一括除外', 'Bulk column exclusions']],
// Ver1.0.6 開発中の名前 (出荷前にユーザー判断で「改訂集計」へ。 host 等の登録済み環境を追随させる)
'TLN_FUNC_DOC_HIS_STATS': [['貢献の集計', 'Contribution statistics']],
// Ver1.0.11: 「物理属性」→「属性」 (属性行は物理属性名と EDM属性の対応。 列名の「物理属性名」はそのまま)
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST': [['業務データ辞書物理属性一覧', 'Business data dictionary attributes']],
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK': [['物理属性CSV一括登録', 'Physical attribute CSV bulk registration'],
// Ver1.0.22: 「物理属性」に戻す (ユーザー指示 2026-10-02。 Ver1.0.11〜1.0.21 の出荷名を追随)
['属性CSV一括登録', 'Attribute CSV bulk registration']]
};
var MENU_DEF = {
athId: 'systemCOMMONWEAL', // メニューフォルダ ID (TLN_M_AUTHORITY)
authAnchorFuncId: 'TLN_FUNC_DOC', // 紐付けグループの導出元 (実行権限)
sortBase: 850, // PRINT_SORT の起点
retiredFuncIds: [], // Ver1.0.11 で廃止した宿題一覧は Ver1.0.18 で復活。 消す画面は今は無い
// ★Ver1.0.19: 版上げで末尾に付いた行を指定の直後へ動かす (registerMenu ⑤)。 ★funcIds より前に書く
// (tools/snapshot_menu_def.py の parser は funcIds の配列より後ろの機能 ID を全部拾う。 コメントにも「funcIds」+ コロンを書かない)
placeAfter: { 'TLN_FUNC_DOC_DOMAIN_TASKS': 'TLN_FUNC_DOC_EDM_ATTR_ASSIGN', 'TLN_FUNC_DOC_DOMAIN_EDM_BULK': 'TLN_FUNC_DOC_DOMAIN_ATTR_BULK',
'TLN_FUNC_DOC_OUT_INDEX': 'TLN_FUNC_DOC' },
urlPrefix: 'TALON/APPLICATION/GENERALFREE/GENERALFREE.xhtml?PARAM_FUNC_ID=',
// ★2026-10-08: 設計書一覧 = サーバ保存の index.html を開く行 (機能ではなく URL の行)。 URL は TFC.serverOutIndexUrl('menu')。
// 置けない環境 (サーバ保存が ZIP のみ / 絶対 URL) では作らず、 既にあれば消す。 配信規則が変われば URL だけ追随する
outIndexFuncId: 'TLN_FUNC_DOC_OUT_INDEX',
// 登録する機能 (この順に PRINT_SORT を振る)。
// ★裏方の機能は載せない: DOMAIN_EDIT (業務データ辞書一覧の [書く] から起動) /
// DOMAIN_SEARCH・EDM_ATTR_SUGGEST (検索子画面) / SETUP (導入時のみ)
funcIds: [
'TLN_FUNC_DOC',
'TLN_FUNC_DOC_OUT_INDEX', // ★2026-10-08: 設計書一覧 (サーバ保存の一覧ページ)。 機能設計書出力の直後
'TLN_FUNC_DOC_EDM',
'TLN_FUNC_DOC_EDM_ATTR_ASSIGN', // Ver1.0.11: 宿題一覧の位置に EDM属性割当
'TLN_FUNC_DOC_DOMAIN_TASKS', // Ver1.0.18: 復活 (業務担当のワークキュー)。 ★Ver1.0.19: EDM属性割当の直後 (ユーザー指示 2026-09-27、 placeAfter も)
'TLN_FUNC_DOC_DOMAIN_LIST',
'TLN_FUNC_DOC_DOMAIN_ALIAS_LIST',
'TLN_FUNC_DOC_DOMAIN_MAINTE',
'TLN_FUNC_DOC_EXCL_MAINTE',
'TLN_FUNC_DOC_EXCL_PICK',
// ★Ver1.0.2 追加。 一番下に配置 (この配列の並び順がそのまま PRINT_SORT の順序になる)
'TLN_FUNC_DOC_DOMAIN_BULK',
'TLN_FUNC_DOC_DOMAIN_ATTR_BULK',
'TLN_FUNC_DOC_DOMAIN_EDM_BULK', // Ver1.0.22: EDM属性CSV一括登録 (宣言だけを CSV で)
// ★Ver1.0.6: 改訂履歴 (履歴照会 DETAIL は一覧の行ボタンから開く裏方なので載せない)
'TLN_FUNC_DOC_DOMAIN_HISTORY',
'TLN_FUNC_DOC_EDM_HISTORY',
'TLN_FUNC_DOC_HIS_STATS'
]
};
function _menuNow() {
return new (Java.type('java.sql.Timestamp'))(
Java.type('java.lang.System').currentTimeMillis());
}
// 監査列 (CREATED_BY / UPDATED_BY) に入れるログインユーザ。 取れなければ機能 ID
function _menuActor() {
try {
if (typeof TALON !== 'undefined' && typeof TALON.getUserInfoMap === 'function') {
var ui = TALON.getUserInfoMap();
if (ui) {
for (var k in ui) {
if (/^(user_?id|login_?user_?id)$/i.test(k)) {
var v = TFC.s(ui[k]);
if (v) return v;
}
}
}
}
} catch (e) { /* 取れなければ既定値 */ }
return 'TLN_FUNC_DOC_SETUP';
}
function _menuCount(sql, params) {
var rows = TFC.selectPS(sql, params);
return (rows.length > 0) ? Number(rows[0]['CNT']) : 0;
}
/**
* 製品の画面を TALON のメニューへ登録する (冪等)。
* @returns {added: 追加した項目数, skipped: 既登録で見送った数, total: 対象数,
* renamed: 旧出荷名から改名した数, moved: placeAfter で動かした数 (Ver1.0.19),
* groups: 紐付けたユーザグループ数, folder: フォルダを新規作成したか}
*/
TFC.registerMenu = function () {
var li = (TFC.uiLang() === 'en') ? 1 : 0;
var athId = MENU_DEF.athId;
var now = _menuNow();
var by = _menuActor();
var prg = 'TLN_FUNC_DOC_SETUP';
var added = 0, skipped = 0, renamed = 0, groups = 0, folder = false;
var i;
// ① メニューフォルダ
if (_menuCount('SELECT COUNT(*) CNT FROM TLN_M_AUTHORITY WHERE FUNC_ATH_ID = ?',
[athId]) === 0) {
TFC.updatePS(
'INSERT INTO TLN_M_AUTHORITY (FUNC_ATH_ID, FUNC_NM, ' +
'CREATED_DATE, CREATED_BY, CREATED_PRG_NM, ' +
'UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)',
[athId, UI_LANG.MENU_GRP[athId][li], now, by, prg, now, by, prg]);
folder = true;
}
// ② ユーザグループ × フォルダ (実行権限を持つグループへ紐付け)
var authRows = TFC.selectPS(
'SELECT DISTINCT FUNC_ATH_ID FROM TLN_M_GENERAL_AUTH WHERE FUNC_ID = ?',
[MENU_DEF.authAnchorFuncId]);
if (authRows.length === 0) {
TALON.getLogger().writeWarn(
'[TFC] registerMenu: ' + MENU_DEF.authAnchorFuncId +
' の機能実行権限が未設定のため、 メニューフォルダをユーザグループへ ' +
'紐付けませんでした (TALON の機能実行権限設定を確認してください)');
}
for (i = 0; i < authRows.length; i++) {
var grpId = TFC.s(authRows[i]['FUNC_ATH_ID']);
if (!grpId) continue;
if (_menuCount('SELECT COUNT(*) CNT FROM TLN_M_GROUP_RELATION ' +
'WHERE FUNC_GRP_ID = ? AND FUNC_ATH_ID = ?',
[grpId, athId]) > 0) continue;
TFC.updatePS(
'INSERT INTO TLN_M_GROUP_RELATION (FUNC_GRP_ID, FUNC_ATH_ID, ' +
'CREATED_DATE, CREATED_BY, CREATED_PRG_NM, ' +
'UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)',
[grpId, athId, now, by, prg, now, by, prg]);
groups++;
}
// ③ 旧出荷名の追随 (値ガード付き改名)。 ★既登録の項目は ④ で skip されるため、
// ここで先に名前だけ現行の出荷名へ揃える。 ja 行は ja へ / en 行は en へ
// (環境の現在言語には寄せない = 言語状態を壊さない)
for (var fid0 in MENU_NM_LEGACY) {
var cur = UI_LANG.MENU_NM[fid0];
if (!cur) continue;
var olds = MENU_NM_LEGACY[fid0];
for (var oi = 0; oi < olds.length; oi++) {
for (var lang = 0; lang < 2; lang++) {
if (olds[oi][lang] === cur[lang]) continue;
renamed += TFC.updatePS(
'UPDATE TLN_M_FUNCTION SET FUNC_NM = ?, UPDATED_DATE = ?, ' +
'UPDATED_BY = ?, UPDATED_PRG_NM = ? WHERE FUNC_ID = ? AND FUNC_NM = ?',
[cur[lang], now, by, prg, fid0, olds[oi][lang]]);
}
}
}
// ④ メニュー項目。
// ★Ver1.0.11: 先に廃止した画面 (宿題一覧) のメニュー行を消す (フォルダを問わない)。 使用済み PRINT_SORT は
// その後に集める = 廃止画面が使っていた位置 (852) を後継 (EDM属性割当、 funcIds で同じ添字) がそのまま引き継ぐ
var retired = 0;
for (i = 0; i < (MENU_DEF.retiredFuncIds || []).length; i++) {
retired += TFC.updatePS('DELETE FROM TLN_M_FUNCTION WHERE FUNC_ID = ?', [MENU_DEF.retiredFuncIds[i]]);
}
// 使用済み PRINT_SORT を集めて空き窓を探す (既登録の行は動かさない = 利用者が並べ替えた順を壊さない)
var used = {};
var sortRows = TFC.selectPS(
'SELECT PRINT_SORT FROM TLN_M_FUNCTION WHERE PRINT_SORT >= ?',
[Java.type('java.lang.Integer').valueOf(MENU_DEF.sortBase)]);
for (i = 0; i < sortRows.length; i++) {
var s = sortRows[i]['PRINT_SORT'];
if (s != null) used[Number(s)] = 1;
}
var removed = 0, urlUpdated = 0, pos = 0;
for (i = 0; i < MENU_DEF.funcIds.length; i++) {
var fid = MENU_DEF.funcIds[i];
// ★2026-10-08: 設計書一覧 (URL の行) は置ける環境でだけ作る。 置けなければ既存の行を消す。 URL は配信規則に追随 (値ガード)
var isIdx = (fid === MENU_DEF.outIndexFuncId);
var appUrl = isIdx ? TFC.serverOutIndexUrl('menu') : (MENU_DEF.urlPrefix + fid);
// ★フォルダを限定せずに探す = 利用者が別フォルダへ移した項目は作り直さない
var exRows = TFC.selectPS('SELECT FUNC_ATH_ID, APP_URL FROM TLN_M_FUNCTION WHERE FUNC_ID = ?', [fid]);
if (isIdx && !appUrl) {
if (exRows.length > 0) removed += TFC.updatePS('DELETE FROM TLN_M_FUNCTION WHERE FUNC_ID = ?', [fid]);
continue; // 位置 (pos) も消費しない = 無い環境では次の行が詰まる
}
if (exRows.length > 0) {
if (isIdx && TFC.s(exRows[0]['APP_URL']) !== appUrl) {
urlUpdated += TFC.updatePS('UPDATE TLN_M_FUNCTION SET APP_URL = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ? WHERE FUNC_ID = ?',
[appUrl, now, by, prg, fid]);
}
skipped++;
pos++;
continue;
}
var sort = MENU_DEF.sortBase + pos;
pos++;
while (used[sort]) sort++;
used[sort] = 1;
TFC.updatePS(
'INSERT INTO TLN_M_FUNCTION (FUNC_ATH_ID, FUNC_ID, FUNC_NM, AUTH_KBN, ' +
'PRINT_SORT, APP_URL, CREATED_DATE, CREATED_BY, CREATED_PRG_NM, ' +
'UPDATED_DATE, UPDATED_BY, UPDATED_PRG_NM, MODIFY_COUNT) ' +
'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)',
[athId, fid, UI_LANG.MENU_NM[fid][li], '1',
Java.type('java.lang.Integer').valueOf(sort),
appUrl, now, by, prg, now, by, prg]);
added++;
}
// ⑤ ★Ver1.0.19: 位置の指定 (MENU_DEF.placeAfter = {動かす機能: この機能の直後})。 版上げの registerMenu は新しい行を末尾の
// 空き窓に足す (④) ので、 「製品フォルダの中で末尾にある行」だけを指定の直後へ動かし、 間の行は相対順を保って 1 つ後ろへずらす。
// 末尾にない行 (= 利用者が並べ替えた) と別フォルダへ移した行は触らない。 まっさらな登録は funcIds の順なので動かす行は無い。
// (実例: Ver1.0.18 で復活した宿題一覧が既存環境では末尾 863 に付いた → EDM属性割当 852 の直後 853 へ)
var moved = 0;
var pa = MENU_DEF.placeAfter || {};
var idPh = [];
for (i = 0; i < MENU_DEF.funcIds.length; i++) idPh.push('?');
for (var mf in pa) {
var rowM = TFC.selectPS('SELECT PRINT_SORT FROM TLN_M_FUNCTION WHERE FUNC_ID = ? AND FUNC_ATH_ID = ?', [mf, athId]);
var rowA = TFC.selectPS('SELECT PRINT_SORT FROM TLN_M_FUNCTION WHERE FUNC_ID = ? AND FUNC_ATH_ID = ?', [pa[mf], athId]);
if (rowM.length === 0 || rowA.length === 0 || rowM[0]['PRINT_SORT'] == null || rowA[0]['PRINT_SORT'] == null) continue;
var sm = Number(rowM[0]['PRINT_SORT']), sa = Number(rowA[0]['PRINT_SORT']);
if (sm <= sa + 1) continue; // 既に直後 (か上にある = 利用者の並び)
var mx = TFC.selectPS('SELECT MAX(PRINT_SORT) MX FROM TLN_M_FUNCTION WHERE FUNC_ATH_ID = ? AND FUNC_ID IN (' + idPh.join(',') + ')',
[athId].concat(MENU_DEF.funcIds));
if (mx.length === 0 || mx[0]['MX'] == null || Number(mx[0]['MX']) !== sm) continue; // 末尾にない = 利用者が置いた位置
var between = TFC.selectPS('SELECT FUNC_ATH_ID, FUNC_ID, PRINT_SORT FROM TLN_M_FUNCTION WHERE PRINT_SORT > ? AND PRINT_SORT < ? ORDER BY PRINT_SORT DESC',
[Java.type('java.lang.Integer').valueOf(sa), Java.type('java.lang.Integer').valueOf(sm)]);
for (var bi = 0; bi < between.length; bi++) {
TFC.updatePS('UPDATE TLN_M_FUNCTION SET PRINT_SORT = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ? WHERE FUNC_ATH_ID = ? AND FUNC_ID = ?',
[Java.type('java.lang.Integer').valueOf(Number(between[bi]['PRINT_SORT']) + 1), now, by, prg,
between[bi]['FUNC_ATH_ID'], between[bi]['FUNC_ID']]);
}
TFC.updatePS('UPDATE TLN_M_FUNCTION SET PRINT_SORT = ?, UPDATED_DATE = ?, UPDATED_BY = ?, UPDATED_PRG_NM = ? WHERE FUNC_ATH_ID = ? AND FUNC_ID = ?',
[Java.type('java.lang.Integer').valueOf(sa + 1), now, by, prg, athId, mf]);
moved++;
}
TALON.getLogger().writeInfo('[TFC] registerMenu: added=' + added + ' skipped=' + skipped +
' renamed=' + renamed + ' retired=' + retired + ' moved=' + moved +
' removed=' + removed + ' urlUpdated=' + urlUpdated + ' groups=' + groups + ' folder=' + folder);
return { added: added, skipped: skipped, renamed: renamed, retired: retired, moved: moved,
removed: removed, urlUpdated: urlUpdated, total: pos, groups: groups, folder: folder };
};
/**
* 外部接続先 (複数DB接続) に対する SELECT を PreparedStatement で実行.
* cfg = TALON.getOtherDBConn('N') で取得した TalonConfig。null なら主 DB (selectPS と同じ)。
* 照合除外ピック画面 (TLN_FUNC_DOC_EXCL_PICK) のカタログ照会など、
* ユーザー入力 (LIKE パターン) を外部 DB のカタログに投げる用途で使う。
* @param cfg TalonConfig (null = 主 DB)
* @param sql プレースホルダ「?」を含む SELECT 文
* @param params JS Array (省略可)
* @returns Array<{COL_NAME: value, ...}> (uppercase キー)
*/
TFC.selectPSByConn = function (cfg, sql, params) {
if (!cfg) return TFC.selectPS(sql, params);
var conn = _getConn(cfg);
var stmt = null, rs = null;
try {
stmt = conn.prepareStatement(sql);
_bindParams(stmt, params);
rs = stmt.executeQuery();
return _readResultSet(rs);
} finally {
if (rs != null) { try { rs.close(); } catch (e) {} }
if (stmt != null) { try { stmt.close(); } catch (e) {} }
// Connection は TALON のトランザクション管理対象のため close しない
}
};
// ============================================================
// DB タイプ判定 (実行時) — JDBC DatabaseMetaData ベース
// 返り値: 'oracle' | 'postgres' | 'mysql' | 'sqlserver' | 'db2'
// | 'cdata' | 'cdata-<subdriver>' (例: 'cdata-salesforce')
// | 'unknown'
//
// 実装は Connection.getMetaData() の URL + productName を見て分類する:
// 1. URL prefix 優先 (確実) jdbc:oracle: / jdbc:postgresql: / jdbc:mysql:
// jdbc:mariadb: / jdbc:sqlserver: / jdbc:microsoft:sqlserver:
// jdbc:db2: / jdbc:cdata:<sub>:
// 2. URL から取れない場合: productName のキーワードでマッチ
// 'Oracle...' → oracle, 'PostgreSQL...' → postgres, 'DB2/...' → db2,
// 'MySQL...' → mysql, 'Microsoft SQL Server' → sqlserver,
// '...CData...' → cdata
// 3. 不明: productName をそのまま小文字化して返す (見えない種別を残す)
//
// キャッシュ無し: getMetaData() は JDBC pool が最適化済みで安価 (probe SQL 4 本より高速)。
// deploy 後の stale を避けるため毎回新規に判定する。
// ============================================================
// 内部: URL prefix と productName から正規化 DB type を導出
function _classifyDbType(url, productName) {
var u = String(url || '').toLowerCase();
var p = String(productName || '').toLowerCase();
// CData: jdbc:cdata:salesforce:User=... → 'cdata-salesforce'
// サブドライバ識別子 (salesforce/rest/excel/...) を含めて返す
var mC = u.match(/^jdbc:cdata:([a-z0-9_]+)/);
if (mC) return 'cdata-' + mC[1];
if (u.indexOf('jdbc:oracle:') === 0) return 'oracle';
if (u.indexOf('jdbc:postgresql:') === 0) return 'postgres';
if (u.indexOf('jdbc:mysql:') === 0) return 'mysql';
if (u.indexOf('jdbc:mariadb:') === 0) return 'mysql';
if (u.indexOf('jdbc:sqlserver:') === 0) return 'sqlserver';
if (u.indexOf('jdbc:microsoft:sqlserver:') === 0) return 'sqlserver';
if (u.indexOf('jdbc:db2:') === 0) return 'db2';
// CData 直接サブプロトコル URL (cdata: prefix 無し): jdbc:googlesheets: / jdbc:salesforce: /
// jdbc:kintone: / jdbc:rest: / jdbc:excel: 等。 CData JDBC ドライバは バージョン/設定で
// URL prefix が 'jdbc:cdata:<sub>:' か 'jdbc:<sub>:' の両形式を取りうるため、
// 既知 RDB 以外の jdbc:<X>: URL は CData サブドライバ '<X>' として扱う
// (sys_tables / sys_tablecolumns カタログにフォールバックして スキーマ取得を試みる)。
var mP = u.match(/^jdbc:([a-z0-9_]+):/);
if (mP) return 'cdata-' + mP[1];
// URL でマッチしない場合は productName で判定
if (p.indexOf('cdata') >= 0) return 'cdata';
if (p.indexOf('oracle') >= 0) return 'oracle';
if (p.indexOf('postgresql') >= 0) return 'postgres';
if (p.indexOf('mysql') >= 0) return 'mysql';
if (p.indexOf('mariadb') >= 0) return 'mysql';
if (p.indexOf('microsoft sql server') >= 0 || p.indexOf('sql server') >= 0) return 'sqlserver';
if (p.indexOf('db2') === 0 || p.indexOf('db2 ') >= 0 || p.indexOf('db2/') >= 0) return 'db2';
// 不明な種別は productName を返す (独自JDBCに対応)
return p || 'unknown';
}
// 内部: URL から データベース/サービス/カタログ名を抽出
// 例:
// jdbc:oracle:thin:@//host:1521/XEPDB1 → 'XEPDB1'
// jdbc:oracle:thin:@host:1521:XEPDB1 → 'XEPDB1' (SID)
// jdbc:postgresql://host:5432/mydb → 'mydb'
// jdbc:mysql://host:3306/mydb?useSSL=false → 'mydb'
// jdbc:sqlserver://host:1433;databaseName=mydb;... → 'mydb'
// jdbc:db2://host:50000/mydb → 'mydb'
// jdbc:cdata:salesforce:User=u@org.com;OAuthClientId=… → '' (catalog 経由で取得)
function _dbNameFromUrl(url) {
if (!url) return '';
var u = String(url);
// Oracle service name (slash 経由)
var mOraSvc = u.match(/jdbc:oracle:[^:]+:@\/\/[^\/]+\/([^?;]+)/i);
if (mOraSvc) return mOraSvc[1];
// Oracle SID (colon 経由)
var mOraSid = u.match(/jdbc:oracle:[^:]+:@[^:\/]+:\d+:([^?;]+)/i);
if (mOraSid) return mOraSid[1];
// PG / MySQL / MariaDB / DB2
var mDb = u.match(/jdbc:(?:postgresql|mysql|mariadb|db2):\/\/[^\/]+\/([^?;]+)/i);
if (mDb) return mDb[1];
// SQL Server (databaseName=xxx 形式)
var mSs = u.match(/databaseName=([^;]+)/i);
if (mSs) return mSs[1];
return '';
}
// 内部: TalonConfig (= getOtherDBConn の戻り値) または null から JDBC metadata 経由で
// DB type / URL / DB 名 / productName を取得。 null = 主 TALON DB。
// 返り値: { type: 'oracle'|...'cdata-salesforce'|'unknown',
// url: string, dbName: string, productName: string }
//
// トランザクション扱い:
// 主 DB はもうユーザー処理がトランザクション内にいる前提。 外部 DB は
// getOtherDBConn 直後の状態で getDataSource().getConnection() が
// TransactionNotYetBegunException を投げる。 そのため
// try dbConfig.begin() → connection → metadata → dbConfig.rollback()
// の順で 検出専用の短命トランザクションを張る。 既に begin 済の場合は
// 2 度目の begin() は失敗するので、 そのときは rollback もスキップする。
function _detectDbInfoViaMetaData(dbConfig) {
var cfg = dbConfig || TALON.getDbConfig();
var beganHere = false;
var info = { type: 'unknown', url: '', dbName: '', productName: '' };
try {
try { cfg.begin(); beganHere = true; } catch (eB) { /* 既に begin 済 */ }
var conn = cfg.getDataSource().getConnection();
var md = conn.getMetaData();
try { info.url = String(md.getURL() || ''); } catch (eU) {}
try { info.productName = String(md.getDatabaseProductName() || ''); } catch (eN) {}
info.type = _classifyDbType(info.url, info.productName);
try { TALON.getLogger().writeInfo('[TFC] detectDbInfo: url=' + _maskConnUrl(info.url) + ', productName=' + info.productName + ', type=' + info.type); } catch (igL) {}
// DB 名: まず Connection.getCatalog() を試す (CData は OAuth Org 名等が入る)、
// 取れなければ URL からパースする (Oracle SERVICE/SID, PG/MySQL/DB2 のパス, SS databaseName)
try {
var cat = String(conn.getCatalog() || '');
if (cat) info.dbName = cat;
} catch (eC) {}
if (!info.dbName) info.dbName = _dbNameFromUrl(info.url);
return info;
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] detectDbInfo: metadata 取得失敗 → unknown フォールバック: ' + e); } catch (ig) {}
return info;
} finally {
if (beganHere) { try { cfg.rollback(); } catch (eR) {} }
}
}
// type 文字列のみ返す互換 API (既存呼出は こちら)
TFC.detectDbType = function () {
return _detectDbInfoViaMetaData(null).type;
};
TFC.detectDbTypeByConn = function (conn) {
if (!conn) return TFC.detectDbType();
return _detectDbInfoViaMetaData(conn).type;
};
// 詳細 info を返す新 API (DB 名等が必要なときに使う)
TFC.detectDbInfo = function () {
return _detectDbInfoViaMetaData(null);
};
TFC.detectDbInfoByConn = function (conn) {
if (!conn) return TFC.detectDbInfo();
return _detectDbInfoViaMetaData(conn);
};
// ============================================================
// ER 図出力 (A5:SQL Mk-2 ネイティブ + DDL 生成)
// ============================================================
// TFC.generateErDiagram(tableNames, opts)
// tableNames: string[] 対象テーブル物理名
// opts: { dbType: 'oracle'|'postgres'|'mysql'|'sqlserver'|'db2'
// (default: opts.conn ? detectDbTypeByConn(conn) : detectDbType()),
// conn: TalonConfig (省略時 = 主 TALON DB)
// TALON.getOtherDBConn('1') 等で取得した外部 DB 接続。
// 指定するとそのコネクションでスキーマ情報を取得する (複数DB接続対応)。
// includeFks: true (default: true),
// lang: 'ja'|'en' (省略時 = _scanLang。 CData SAP Gateway の $metadata の言語 = sap-language) }
// 戻り値: { meta: {tables, fks}, a5er: string, ddl: string }
// テーブル定義・FK・テーブル/列コメントを TalonDbUtil.select で DB スキーマビューから取得し、
// .a5er (A5:SQL Mk-2 ネイティブ INI 風 + UTF-8 BOM + CRLF) と .sql (DDL) を生成。
TFC.generateErDiagram = function (tableNames, opts) {
opts = opts || {};
var conn = opts.conn || null;
var dbType = (opts.dbType || (conn ? TFC.detectDbTypeByConn(conn) : TFC.detectDbType()) || 'oracle').toLowerCase();
// 'postgresql' エイリアスを 'postgres' に正規化
if (dbType === 'postgresql') dbType = 'postgres';
// 'mysql_linux' / 'mysql_windows' → 'mysql'
if (dbType.indexOf('mysql') === 0) dbType = 'mysql';
// 'cdata-salesforce' / 'cdata-rest' / ... → 'cdata' (sys_* カタログは 全サブドライバ共通)
// サブドライバ名は FK スキーマ系統の選択 (Salesforce = Referenced* 系) に使うため保持
var cdataSub = '';
if (dbType.indexOf('cdata-') === 0) {
cdataSub = dbType.substring(6);
dbType = 'cdata';
}
var includeFks = opts.includeFks !== false;
// 未知 DB: カタログビューが どの dialect とも 合致しない → テーブル名スタブだけ返す
// (依存関係タブ / 全設定タブの DB バッジ表示用 = accessDb / dbType の伝播)
if (dbType === 'unknown') {
var stubTables = [];
for (var sti = 0; sti < tableNames.length; sti++) {
stubTables.push({ name: tableNames[sti], comment: '', cols: [], pkCols: [] });
}
return { meta: { tables: stubTables, fks: [] }, a5er: '', ddl: '' };
}
// CData も SYS カタログ経由で 通常の DB と同じく メタ取得する。 catalog query が
// 失敗 (= 一部 CData ドライバで sys_* が無い場合) は スタブにフォールバック。
if (dbType === 'cdata') {
try {
var metaC = _fetchErMeta(tableNames, dbType, includeFks, conn, cdataSub, opts.lang || _scanLang);
return {
meta: metaC,
a5er: _erToA5er(metaC),
ddl: _erToDdl(metaC, dbType)
};
} catch (eCD) {
try { TALON.getLogger().writeWarn('[TFC] CData ER メタ取得失敗 → テーブル名スタブにフォールバック: ' + eCD); } catch (ig) {}
var stubC = [];
for (var stj = 0; stj < tableNames.length; stj++) {
stubC.push({ name: tableNames[stj], comment: '', cols: [], pkCols: [] });
}
return { meta: { tables: stubC, fks: [] }, a5er: '', ddl: '' };
}
}
var meta = _fetchErMeta(tableNames, dbType, includeFks, conn);
return {
meta: meta,
a5er: _erToA5er(meta),
ddl: _erToDdl(meta, dbType)
};
};
// ============================================================
// テーブル名 正規化キー (★抜本対応 2026-05-29)
// ============================================================
// 「表示用名前」 と「検索用キー」 の責任分離。
// - 表示 (HTML / DDL / A5er / tooltip) : DB 由来の元 case をそのまま使う
// (例: PG なら lowercase / Oracle なら UPPER / Salesforce 等 case-sensitive
// データソースでは PascalCase など、 取得元のものをそのまま見せる)
// - 検索 / Map キー / HTML anchor ID : _tblKey() で UPPER 正規化 (環境横断で安定)
//
// すべての内部 Map (erTableBgRead/Write / funcTableRefs / byTable / fkChildCols /
// physMatch.byTable など) は _tblKey() を通したキーで統一する。 anchor ID
// (er-diagram.html#tbl-XXX) も _tblKey() で統一することで、 環境別の case 違いに
// 関係なくリンクが解決する。
TFC._tblKey = function (name) { return String(name || '').toUpperCase(); };
// CData (Salesforce) の Description boilerplate からラベルを抽出する。
// Salesforce ドライバは sys_tablecolumns.ColumnLabel を持たない代わりに、
// Description にフィールドラベルを定型文で包んで返す:
// JA: "'顧客 ID' ラベルはこのフィールドに一致します。" → "顧客 ID"
// EN: "Label 'Account ID' corresponds to this field." → "Account ID"
// 定型文にマッチしない Description (= 利用者が設定した説明等) はそのまま返す。
function _cdataCommentToLabel(s) {
if (!s) return s;
var str = String(s);
var m = str.match(/^'(.+)'\s*ラベルはこのフィールドに一致します。?$/);
if (m) return m[1];
m = str.match(/^Label\s+'(.+)'\s+corresponds\s+to\s+this\s+field\.?$/i);
if (m) return m[1];
return s;
}
// ============================================================
// CData SAP Gateway: OData $metadata の注釈 (SAP__common.Label / QuickInfo) で論理名を補う (2026-10-09)
// CData のカタログ (sys_tables / sys_tablecolumns の Description) は SAP の OData v4 サービスでは空で、
// 接続プロパティ UseDisplayNames も効かない (発注サービスで実測)。 ラベルは SAP の $metadata に
// <Annotation Term="SAP__common.Label" String="購買伝票"/> の形で入っているので、 接続文字列
// (DatabaseMetaData.getURL() = jdbc:sapgateway:URL=…;User=…;Password=…;CustomURLParams="sap-client=100";…)
// から URL と Basic 認証を取り、 出力言語の sap-language (JA / EN) で $metadata を読む。
// 取れないとき (Basic 以外 / 証明書 / 到達不能 / 200 以外) はログだけ出して従来どおり (ラベル無し)。
// テーブル名 = EntitySet 名。 CData の結合ビュー A__B は A + '_' + ナビゲーション名 ('_B') で、
// その列 A_x は A の x、 それ以外は B (無ければ同名の属性を持つエンティティ) で引く。 Etag は CData の技術列。
// 論理名 = Label、 説明 = QuickInfo。 DB_COMMENT_SEP (TLN_GENERAL) が設定されているときだけ「論理名<区切り>説明」に合成する
// (本体の _logicalNameFromComment / _descFromComment と ER ライブラリの _a5erSplitComment がこの形を読む)。
// ★2026-10-14 (ユーザー決定 案 A): $metadata にラベルがあれば、 ドライバのカタログが入れた説明より優先する。 OData v2 サービスでは CData が
// sap:quickinfo を Description として、 接続の利用者のログオン言語 (出力言語とは無関係。 cw03 は英語) で返すため、 「空の説明だけ埋める」では
// 日本語出力でも英語のままだった (ZI_EKBE3 の Item = "Item Number of Purchasing Document")。 ラベルの無いテーブル / 列だけドライバの説明を残す
// (SAP 側に訳が無い項目は英語のまま = ユーザー了承)。 v4 はドライバの説明が空なので結果は変わらない。
// 純関数 = tests/test_sap_meta_labels.py (Node)。 HTTP は TFC._sapMetaFetch (Java)。 資格情報はログに出さない。
// ============================================================
// 接続文字列 (jdbc:<sub>:Key=Value;Key="a;b";…) → { key(小文字): value }。 引用符の中の ; は区切らない
function _cdataConnProps(connUrl) {
var s = String(connUrl || '');
var pm = s.match(/^jdbc:[A-Za-z0-9_]+:/);
if (pm) s = s.substring(pm[0].length);
var out = {}, cur = '', q = false;
function flush() {
var i = cur.indexOf('=');
if (i > 0) {
var k = cur.substring(0, i).trim().toLowerCase();
var v = cur.substring(i + 1).trim();
if (v.length >= 2 && v.charAt(0) === '"' && v.charAt(v.length - 1) === '"') v = v.substring(1, v.length - 1);
out[k] = v;
}
cur = '';
}
for (var i = 0; i < s.length; i++) {
var ch = s.charAt(i);
if (ch === '"') { q = !q; cur += ch; continue; }
if (ch === ';' && !q) { flush(); continue; }
cur += ch;
}
if (cur) flush();
return out;
}
// ログ用: 接続文字列の秘密 (Password 等) を伏せる
function _maskConnUrl(u) {
return String(u || '').replace(/(Password|Pwd|OAuthClientSecret|OAuthAccessToken|OAuthRefreshToken|APIKey|AccessKey|SecretKey|ProxyPassword)=[^;]*/gi, '$1=***');
}
// サービスの URL (末尾 / 付き)。 URL がホストまでで Namespace / Service に分かれているときは /sap/opu/odata/<ns>/<svc>/ を組む
function _sapMetaServiceUrl(props) {
var u = String(props.url || '').trim();
if (!/^https?:\/\//i.test(u)) return '';
var ns = String(props.namespace || '').trim(), sv = String(props.service || '').trim();
if (sv && u.toLowerCase().indexOf('/sap/opu/odata') < 0) {
u = u.replace(/\/+$/, '') + '/sap/opu/odata/' + (ns ? ns + '/' : '') + sv;
}
if (u.charAt(u.length - 1) !== '/') u += '/';
return u;
}
// $metadata のクエリ: CustomURLParams (sap-client=100 等) + 出力言語の sap-language (既に指定されていれば足さない)
function _sapMetaQuery(customParams, lang) {
var q = String(customParams || '').replace(/^\?/, '').trim();
if (!/(^|&)sap-language=/i.test(q)) q += (q ? '&' : '') + 'sap-language=' + (String(lang || 'ja').toLowerCase() === 'en' ? 'EN' : 'JA');
return q;
}
function _xmlUnesc(s) {
return String(s || '')
.replace(/&#x([0-9A-Fa-f]+);/g, function (m0, h) { return String.fromCharCode(parseInt(h, 16)); })
.replace(/&#([0-9]+);/g, function (m0, d) { return String.fromCharCode(parseInt(d, 10)); })
.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&');
}
function _xmlAttr(tag, name) {
var m = String(tag || '').match(new RegExp('(?:^|\\s)' + name + '="([^"]*)"'));
return m ? _xmlUnesc(m[1]) : '';
}
// $metadata (OData v4 の Annotations / v2 の sap:label 属性) → { sets: {EntitySet名: 型名}, types: {型名: {label, quick, props: {属性名: {label, quick, heading}}, nav: {ナビ名: 型名}}} }
function _sapMetaParse(xml) {
var x = String(xml || '');
var res = { sets: {}, types: {} };
if (!x) return res;
function local(n) {
n = String(n || '').replace(/^Collection\(/, '').replace(/\)$/, '');
var i = n.lastIndexOf('.');
return i >= 0 ? n.substring(i + 1) : n;
}
// Common 語彙の別名 (edmx:Include の Alias)。 無ければ SAP__common / Common / 完全名で受ける
var aliases = {};
var incRe = /<(?:edmx:)?Include\b[^>]*>/g, im;
while ((im = incRe.exec(x)) !== null) {
var ns = _xmlAttr(im[0], 'Namespace'), al = _xmlAttr(im[0], 'Alias');
if (ns && al) aliases[al] = ns;
}
function isCommon(term, name) {
var i = term.lastIndexOf('.');
if (i < 0 || term.substring(i + 1) !== name) return false;
var pre = term.substring(0, i);
var full = aliases[pre] || pre;
return full === 'com.sap.vocabularies.Common.v1' || pre === 'SAP__common' || pre === 'Common';
}
// 注釈 (<Annotation Term=… String=…/> か <Annotation Term=…><String>…</String></Annotation>) から Label / QuickInfo / Heading
function annos(body) {
var o = { label: '', quick: '', heading: '' };
var re = /<Annotation\b([^>]*?)(?:\/>|>([\s\S]*?)<\/Annotation>)/g, am;
while ((am = re.exec(body)) !== null) {
var term = _xmlAttr(am[1], 'Term');
var val = _xmlAttr(am[1], 'String');
if (!val && am[2]) { var sm = am[2].match(/<String>([\s\S]*?)<\/String>/); if (sm) val = _xmlUnesc(sm[1]); }
if (!val) continue;
if (isCommon(term, 'Label')) o.label = val;
else if (isCommon(term, 'QuickInfo')) o.quick = val;
else if (isCommon(term, 'Heading')) o.heading = val;
}
return o;
}
function typeOf(name) { if (!res.types[name]) res.types[name] = { label: '', quick: '', props: {}, nav: {} }; return res.types[name]; }
function propOf(t, p) { if (!t.props[p]) t.props[p] = { label: '', quick: '', heading: '' }; return t.props[p]; }
function merge(dst, src) { if (src.label) dst.label = src.label; if (src.quick) dst.quick = src.quick; if (src.heading) dst.heading = src.heading; }
// EntityType: 属性 / ナビゲーション / v2 の sap:label 属性 / 中に書かれた注釈
var etRe = /<EntityType\b([^>]*)>([\s\S]*?)<\/EntityType>/g, em;
while ((em = etRe.exec(x)) !== null) {
var tn = _xmlAttr(em[1], 'Name');
if (!tn) continue;
var t = typeOf(tn);
var v2l = _xmlAttr(em[1], 'sap:label');
if (v2l) t.label = v2l;
var body = em[2];
var pRe = /<Property\b([^>]*?)(?:\/>|>([\s\S]*?)<\/Property>)/g, pmm;
while ((pmm = pRe.exec(body)) !== null) {
var pn = _xmlAttr(pmm[1], 'Name');
if (!pn) continue;
var pr = propOf(t, pn);
var l2 = _xmlAttr(pmm[1], 'sap:label'), q2 = _xmlAttr(pmm[1], 'sap:quickinfo');
if (l2) pr.label = l2;
if (q2) pr.quick = q2;
if (pmm[2]) merge(pr, annos(pmm[2]));
}
var nRe = /<NavigationProperty\b([^>]*?)(?:\/>|>[\s\S]*?<\/NavigationProperty>)/g, nm;
while ((nm = nRe.exec(body)) !== null) {
var nn = _xmlAttr(nm[1], 'Name'), nt = _xmlAttr(nm[1], 'Type');
if (nn && nt) t.nav[nn] = local(nt);
}
}
// EntitySet → 型 (v2 の sap:label はセット側にも付く)
var esRe = /<EntitySet\b([^>]*?)(?:\/>|>([\s\S]*?)<\/EntitySet>)/g, sm2;
while ((sm2 = esRe.exec(x)) !== null) {
var sn = _xmlAttr(sm2[1], 'Name'), st = local(_xmlAttr(sm2[1], 'EntityType'));
if (!sn || !st) continue;
res.sets[sn] = st;
var sl = _xmlAttr(sm2[1], 'sap:label');
if (sl && !typeOf(st).label) typeOf(st).label = sl;
}
// 外出しの注釈 <Annotations Target="別名.型/属性"> / <Annotations Target="別名.型">
var aRe = /<Annotations\b([^>]*)>([\s\S]*?)<\/Annotations>/g, xm;
while ((xm = aRe.exec(x)) !== null) {
var tg = _xmlAttr(xm[1], 'Target');
if (!tg) continue;
var slash = tg.indexOf('/');
var tPart = slash >= 0 ? tg.substring(0, slash) : tg, pPart = slash >= 0 ? tg.substring(slash + 1) : '';
var tnm = local(tPart);
if (!res.types[tnm]) continue; // コンテナ / 関数などは対象外
var a = annos(xm[2]);
if (pPart) merge(propOf(res.types[tnm], pPart), a); else merge(res.types[tnm], a);
}
return res;
}
// CData のテーブル名 / 列名 → { label, quick } (無ければ null)。 colName 省略 = テーブル (エンティティ) のラベル
function _sapMetaLookup(sm, tableName, colName) {
var tn = String(tableName || ''), cn = (colName === undefined || colName === null) ? '' : String(colName);
var base = tn, navn = '', ix = tn.indexOf('__');
if (ix > 0) { base = tn.substring(0, ix); navn = tn.substring(ix + 2); }
var tA = sm.sets[base] ? sm.types[sm.sets[base]] : null;
var tB = null;
if (tA && navn) tB = sm.types[tA.nav['_' + navn] || tA.nav[navn]] || null;
if (!cn) {
if (!tA) return null;
if (!navn) return tA.label ? { label: tA.label, quick: tA.quick } : null;
if (!tB || !tA.label || !tB.label) return null;
return { label: tA.label + ' × ' + tB.label, quick: '' };
}
if (cn === 'Etag') return null;
var cands = [];
if (tA && navn && cn.indexOf(base + '_') === 0) cands.push([tA, cn.substring(base.length + 1)]);
if (tB) cands.push([tB, cn]);
if (tA) cands.push([tA, cn]);
for (var i = 0; i < cands.length; i++) {
var p = cands[i][0].props[cands[i][1]];
if (p && p.label) return { label: p.label, quick: p.quick };
}
if (!tA) return null; // $metadata に無いテーブルは同名の属性でも補わない
for (var k in sm.types) {
if (sm.types.hasOwnProperty(k) && sm.types[k].props[cn] && sm.types[k].props[cn].label) {
return { label: sm.types[k].props[cn].label, quick: sm.types[k].props[cn].quick };
}
}
return null;
}
// meta.tables[].comment / cols[].comment が空のところだけ補う。 sep があれば「論理名<sep>説明」。 返り値 = 補った数
function _sapMetaApply(meta, sm, sep) {
// $metadata のラベル (出力言語) があればそれを採り (ドライバの説明があっても置き換える)、 無いときだけ既存の説明を残す。 戻り値 = 書き換えた数
var n = 0;
function compose(r) {
if (!r || !r.label) return '';
var q = String(r.quick || '');
return (sep && q && q !== r.label) ? r.label + sep + q : r.label;
}
var tables = (meta && meta.tables) || [];
for (var i = 0; i < tables.length; i++) {
var t = tables[i];
var tc = compose(_sapMetaLookup(sm, t.name));
if (tc && tc !== t.comment) { t.comment = tc; n++; }
var cols = t.cols || [];
for (var j = 0; j < cols.length; j++) {
var c = cols[j];
var cc = compose(_sapMetaLookup(sm, t.name, c.name));
if (cc && cc !== c.comment) { c.comment = cc; n++; }
}
}
return n;
}
// TLN_GENERAL / DB_COMMENT_SEP (本体の _getDbCommentSep と同じ値。 共通JS はリクエストをまたいで残るのでキャッシュしない)
TFC.dbCommentSep = function () {
try {
var rows = TFC.selectU("SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = 'TLN_GENERAL' AND KEY_CODE = 'DB_COMMENT_SEP'");
return (rows && rows.size() > 0) ? TFC.s(rows[0]['DSP1']) : '';
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] DB_COMMENT_SEP 取得失敗: ' + e); } catch (ig) {}
return '';
}
};
// $metadata を HTTP で読む (Java)。 戻り = XML 文字列 (取れないときは '')。 同じ URL は 10 分キャッシュ。 証明書は JVM の信頼ストアで検証する
var _sapMetaCache = {};
var _SAP_META_TTL_MS = 600000;
TFC._sapMetaFetch = function (connUrl, lang) {
var props = _cdataConnProps(connUrl);
var svc = _sapMetaServiceUrl(props);
if (!svc) return '';
var scheme = String(props.authscheme || (props.user ? 'Basic' : '')).toLowerCase();
if (scheme !== 'basic') {
try { TALON.getLogger().writeInfo('[TFC] sapgateway $metadata: AuthScheme=' + scheme + ' は未対応 (ラベル無しで続行)'); } catch (ig0) {}
return '';
}
var full = svc + '$metadata?' + _sapMetaQuery(props.customurlparams, lang);
var now = new Date().getTime();
var hit = _sapMetaCache[full];
if (hit && (now - hit.at) < _SAP_META_TTL_MS) return hit.xml;
var shown = full.replace(/^(https?:\/\/)[^\/@]*@/, '$1'); // 万一 userinfo 形式でも伏せる
var xml = '';
var ins = null;
try {
var JURL = Java.type('java.net.URL');
var JString = Java.type('java.lang.String');
var con = new JURL(full).openConnection();
var HttpsConn = Java.type('javax.net.ssl.HttpsURLConnection');
if (con instanceof HttpsConn) {
// Payara は javax.net.ssl.keyStore (s1as の自己署名) を JVM 既定にしているので、 既定の SSLSocketFactory だと
// クライアント証明書を求めるサーバ (SAP ICM の verify_client=1) に s1as を提示して certificate_unknown で切られる
// (cw03 実測 2026-10-09)。 鍵は出さず (KeyManager 無し)、 サーバ証明書の検証は JVM 既定の信頼ストアのまま
var SSLContext = Java.type('javax.net.ssl.SSLContext');
var sc = SSLContext.getInstance('TLS');
sc.init(null, null, null);
con.setSSLSocketFactory(sc.getSocketFactory());
}
con.setConnectTimeout(10000);
con.setReadTimeout(60000);
con.setRequestProperty('Accept', 'application/xml');
var user = String(props.user || ''), pw = String(props.password || '');
if (user) {
var B64 = Java.type('java.util.Base64');
con.setRequestProperty('Authorization', 'Basic ' + B64.getEncoder().encodeToString(new JString(user + ':' + pw).getBytes('UTF-8')));
}
var code = con.getResponseCode();
if (code !== 200) {
try { TALON.getLogger().writeWarn('[TFC] sapgateway $metadata: HTTP ' + code + ' (' + shown + ') → ラベル無しで続行'); } catch (ig1) {}
} else {
ins = con.getInputStream();
var bos = new (Java.type('java.io.ByteArrayOutputStream'))();
var ByteArr = Java.type('byte[]');
var buf = new ByteArr(65536);
var r;
while ((r = ins.read(buf)) > 0) bos.write(buf, 0, r);
xml = String(new JString(bos.toByteArray(), 'UTF-8'));
try { TALON.getLogger().writeInfo('[TFC] sapgateway $metadata: ' + xml.length + ' 文字 (' + shown + ')'); } catch (ig2) {}
}
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] sapgateway $metadata: 取得失敗 (' + shown + '): ' + e + ' → ラベル無しで続行'); } catch (ig3) {}
xml = '';
} finally {
if (ins) { try { ins.close(); } catch (igc) {} }
}
_sapMetaCache[full] = { at: now, xml: xml };
return xml;
};
// _fetchErMeta から呼ぶ: 接続 (TalonConfig) の URL で $metadata を読み、 meta のテーブル / 列コメントを補う。 失敗はログだけ
function _sapMetaDecorate(meta, conn, lang) {
var connUrl = _detectDbInfoViaMetaData(conn).url;
if (!connUrl) return 0;
var xml = TFC._sapMetaFetch(connUrl, lang);
if (!xml) return 0;
var n = _sapMetaApply(meta, _sapMetaParse(xml), TFC.dbCommentSep());
try { TALON.getLogger().writeInfo('[TFC] sapgateway $metadata: ラベルを ' + n + ' 件補った (lang=' + lang + ')'); } catch (ig) {}
return n;
}
// テーブル メタデータ取得 (DB エンジン別)
// 返り値: {tables: [{name, comment, cols:[{name, type, len, prec, scale, nullable, isPk}]}],
// fks: [{childTable, childCol, parentTable, parentCol, name}]}
//
// `tables[i].name` は DB 由来の元 case を保持する。 内部 Map のキーとしては
// _tblKey(t.name) を使うこと。
function _fetchErMeta(tableNames, dbType, includeFks, conn, cdataSub, lang) {
var meta = { tables: [], fks: [] };
if (!tableNames || tableNames.length === 0) return meta;
// 接続別 SELECT。 conn=null/undefined のときは主 TALON DB (TFC.selectU)。
function sel(sql) { return conn ? TFC.selectUByConn(conn, sql) : TFC.selectU(sql); }
// SQL の IN 句用に bind 化されない文字列リテラルでエスケープ (常に大文字化)
// inListExact は呼出側から渡された元 case のままの IN リスト。 CData では
// UPPER(TableName) 比較だと フィルタがドライバにプッシュダウンされず 全テーブルの
// メタデータ列挙 (Salesforce 等では数分) になるため、 exact-match を優先する。
var inList = '';
var inListExact = '';
var upperNames = [];
for (var i = 0; i < tableNames.length; i++) {
var nameUp = TFC._tblKey(tableNames[i]).replace(/'/g, "''");
upperNames.push(nameUp);
if (i > 0) { inList += ','; inListExact += ','; }
inList += "'" + nameUp + "'";
inListExact += "'" + String(tableNames[i] || '').replace(/'/g, "''") + "'";
}
var queries = _erQueries(dbType, inList, inListExact, cdataSub);
// 列定義 (selectUByConn 経由で PG の lowercase キー → uppercase 化)
var colRows = sel(queries.cols);
// CData の exact-match で 0 件 (= 設定由来の case が実テーブル名と不一致) の場合は
// UPPER() 比較版で再試行する (全メタデータ列挙になるため低速だが確実)
if (dbType === 'cdata' && colRows.size() === 0 && inListExact !== inList) {
try { TALON.getLogger().writeWarn('[TFC] CData exact-match 0 件 → UPPER 比較で再試行: ' + inListExact); } catch (igUx) {}
queries = _erQueries(dbType, inList, null, cdataSub);
colRows = sel(queries.cols);
}
var byTable = {};
for (var ci = 0; ci < colRows.size(); ci++) {
var r = colRows[ci];
var tn = TFC.s(r['TABLE_NAME']); // 元 case 保持 (表示用)
var tnKey = TFC._tblKey(tn); // 内部 Map キー (UPPER)
if (!byTable[tnKey]) byTable[tnKey] = { name: tn, comment: '', cols: [], colByName: {} };
// CData: 列コメント (Description) は cols クエリに統合済 (COL_COMMENT)。
// ボイラープレートを除外し、 定型文からラベル (= 論理名相当) を抽出する。
var colCmt = '';
if (dbType === 'cdata') {
var rawCc = TFC.s(r['COL_COMMENT']);
if (rawCc) {
var lcCc = rawCc.toLowerCase().replace(/\s+/g, ' ').replace(/\.\s*$/, '').trim();
if (lcCc !== 'autogenerated' && lcCc !== 'no description' && lcCc !== 'no information') {
colCmt = _cdataCommentToLabel(rawCc);
}
}
}
var colObj = {
name: TFC.s(r['COLUMN_NAME']),
type: TFC.s(r['DATA_TYPE']),
len: TFC.s(r['DATA_LENGTH']),
prec: TFC.s(r['DATA_PRECISION']),
scale: TFC.s(r['DATA_SCALE']),
nullable: TFC.s(r['NULLABLE']) !== 'N',
isPk: TFC.s(r['IS_PK']) === 'Y',
comment: colCmt
};
byTable[tnKey].cols.push(colObj);
byTable[tnKey].colByName[colObj.name] = colObj;
}
// テーブルコメント (オプション)
// ※ CData はサブドライバごとにカタログスキーマが異なるため、 コメント / FK は
// クエリ単位で非致命化する (失敗しても列定義だけは生かす)。
if (queries.comments) {
try {
var cmtRows = sel(queries.comments);
for (var mi = 0; mi < cmtRows.size(); mi++) {
var cr = cmtRows[mi];
var tn2 = TFC._tblKey(TFC.s(cr['TABLE_NAME']));
if (byTable[tn2]) byTable[tn2].comment = TFC.s(cr['COMMENTS']);
}
} catch (eCmt) {
try { TALON.getLogger().writeWarn('[TFC] テーブルコメント取得失敗 (続行): ' + eCmt); } catch (igC1) {}
}
}
// 列コメント (= 論理名相当) を取得して各列に紐付け
if (queries.colComments) {
try {
var ccRows = sel(queries.colComments);
for (var ki = 0; ki < ccRows.size(); ki++) {
var ccr = ccRows[ki];
var tn3 = TFC._tblKey(TFC.s(ccr['TABLE_NAME']));
var cn3 = TFC.s(ccr['COLUMN_NAME']);
var cmt3 = TFC.s(ccr['COMMENTS']);
// CData: Description の定型文からフィールドラベルを抽出
if (dbType === 'cdata') cmt3 = _cdataCommentToLabel(cmt3);
if (byTable[tn3] && byTable[tn3].colByName[cn3]) {
byTable[tn3].colByName[cn3].comment = cmt3;
}
}
} catch (eCc) {
try { TALON.getLogger().writeWarn('[TFC] 列コメント取得失敗 (続行): ' + eCc); } catch (igC2) {}
}
}
// ★テスター指摘 No.95: 索引メタ (IndexInfo 出力用)。 取得失敗しても続行 (非致命)
if (queries.indexes) {
try {
var ixRows = sel(queries.indexes);
for (var xi = 0; xi < ixRows.size(); xi++) {
var xr = ixRows[xi];
var tnx = TFC._tblKey(TFC.s(xr['TABLE_NAME']));
if (!byTable[tnx]) continue;
var tIdx = byTable[tnx];
if (!tIdx.indexes) { tIdx.indexes = []; tIdx._ixByName = {}; }
var ixn = TFC.s(xr['INDEX_NAME']);
var ixRec = tIdx._ixByName[ixn];
if (!ixRec) {
ixRec = { name: ixn, unique: TFC.s(xr['IS_UNIQUE']) === 'Y',
// uniqCons: ユニーク制約バック (uniq=2 / ADD CONSTRAINT UNIQUE)
uniqCons: TFC.s(xr['IS_UNIQ_CONS']) === 'Y', cols: [] };
tIdx._ixByName[ixn] = ixRec;
tIdx.indexes.push(ixRec);
}
ixRec.cols.push(TFC.s(xr['COLUMN_NAME']));
}
} catch (eIx) {
try { TALON.getLogger().writeWarn('[TFC] 索引メタ取得失敗 (続行): ' + eIx); } catch (igIx) {}
}
// 作業用の名前引きマップは下流 (erMeta / _erMetaForEdm) へ持ち出さない
for (var tnc in byTable) {
if (byTable.hasOwnProperty(tnc) && byTable[tnc]._ixByName) delete byTable[tnc]._ixByName;
}
}
// 並び順: tableNames の指定順を維持 (upperNames で照合)
for (var ti = 0; ti < upperNames.length; ti++) {
var name = upperNames[ti];
if (byTable[name]) meta.tables.push(byTable[name]);
}
// ★CData SAP Gateway (2026-10-09): OData $metadata の注釈でテーブル / 列の論理名 (コメント) を補う。 取れなければそのまま
if (dbType === 'cdata' && cdataSub === 'sapgateway') {
try { _sapMetaDecorate(meta, conn, lang || _scanLang); }
catch (eSm) { try { TALON.getLogger().writeWarn('[TFC] sapgateway $metadata の適用に失敗 (ラベル無しで続行): ' + eSm); } catch (igSm) {} }
}
// FK: childTable / parentTable は表示にも検索にも使うため、 元 case 保持。
// 利用側で必要に応じて _tblKey() で正規化する。
// CData: sys_foreignkeys のスキーマが 2 系統ある
// (ForeignKeyTable/PrimaryKeyTable 系 と TableName/ReferencedTableName 系)。
// 本命が失敗したら fksFallback で再試行し、 それも失敗したら FK 無しで続行する。
if (includeFks && queries.fks) {
var fkRows = null;
try {
fkRows = sel(queries.fks);
} catch (eFk1) {
if (queries.fksFallback) {
try { TALON.getLogger().writeWarn('[TFC] FK クエリ失敗 → 代替スキーマで再試行: ' + eFk1); } catch (igF1) {}
try { fkRows = sel(queries.fksFallback); }
catch (eFk2) {
try { TALON.getLogger().writeWarn('[TFC] FK 代替クエリも失敗 (FK 無しで続行): ' + eFk2); } catch (igF2) {}
}
} else {
try { TALON.getLogger().writeWarn('[TFC] FK クエリ失敗 (FK 無しで続行): ' + eFk1); } catch (igF3) {}
}
}
if (fkRows) {
for (var fi = 0; fi < fkRows.size(); fi++) {
var fr = fkRows[fi];
meta.fks.push({
childTable: TFC.s(fr['CHILD_TABLE']),
childCol: TFC.s(fr['CHILD_COL']),
parentTable: TFC.s(fr['PARENT_TABLE']),
parentCol: TFC.s(fr['PARENT_COL']),
name: TFC.s(fr['CONSTRAINT_NAME'])
});
}
}
}
return meta;
}
function _erQueries(dbType, inList, inListExact, cdataSub) {
// 大文字小文字不一致対策: 全 IN 比較を UPPER() 両側で行う。
// inList は呼出側で常に大文字化済。 各 DB ビュー側の値も UPPER 関数を適用。
// inListExact (元 case の IN リスト) は CData 専用: UPPER() 比較だと CData が
// フィルタをドライバにプッシュダウンできず全テーブルのメタデータ列挙になるため、
// exact-match で照会する (RDB 系カタログビューは高速なので UPPER のまま)。
if (dbType === 'oracle') {
return {
cols:
"SELECT c.table_name, c.column_name, c.data_type, c.data_length, " +
" c.data_precision, c.data_scale, c.nullable, c.column_id, " +
" CASE WHEN pk.column_name IS NOT NULL THEN 'Y' ELSE 'N' END AS is_pk " +
"FROM user_tab_columns c " +
"LEFT JOIN ( " +
" SELECT cc.table_name, cc.column_name " +
" FROM user_constraints uc " +
" JOIN user_cons_columns cc ON uc.constraint_name = cc.constraint_name " +
" WHERE uc.constraint_type = 'P' " +
") pk ON pk.table_name = c.table_name AND pk.column_name = c.column_name " +
"WHERE UPPER(c.table_name) IN (" + inList + ") " +
"ORDER BY c.table_name, c.column_id",
// ★テスター指摘 No.95: 索引 (PK 索引は A5M2 側で別管理のため除外)。
// FBI (関数索引) は列名が SYS_NC 内部名になるため、 DOMAIN 索引 (Oracle Text 等)
// とあわせて除外。 UNUSABLE (無効化) も出力しない。
indexes:
"SELECT i.table_name AS TABLE_NAME, i.index_name AS INDEX_NAME, " +
" CASE WHEN i.uniqueness = 'UNIQUE' THEN 'Y' ELSE 'N' END AS IS_UNIQUE, " +
// ユニーク制約バックの索引 (A5M2 IndexInfo uniq=2 / DDL は ADD CONSTRAINT UNIQUE)
" CASE WHEN EXISTS (SELECT 1 FROM user_constraints uq " +
" WHERE uq.constraint_type = 'U' AND uq.index_name = i.index_name) " +
" THEN 'Y' ELSE 'N' END AS IS_UNIQ_CONS, " +
" ic.column_name AS COLUMN_NAME " +
"FROM user_indexes i " +
"JOIN user_ind_columns ic ON ic.index_name = i.index_name " +
"WHERE UPPER(i.table_name) IN (" + inList + ") " +
"AND i.index_type NOT LIKE 'FUNCTION-BASED%' " +
"AND i.index_type <> 'DOMAIN' " +
"AND i.status <> 'UNUSABLE' " +
"AND NOT EXISTS (SELECT 1 FROM user_constraints uc " +
" WHERE uc.constraint_type = 'P' AND uc.index_name = i.index_name) " +
"ORDER BY i.table_name, i.index_name, ic.column_position",
comments:
"SELECT table_name, comments " +
"FROM user_tab_comments " +
"WHERE UPPER(table_name) IN (" + inList + ")",
colComments:
"SELECT table_name, column_name, comments " +
"FROM user_col_comments " +
"WHERE UPPER(table_name) IN (" + inList + ") " +
"AND comments IS NOT NULL",
fks:
"SELECT a.table_name AS child_table, a.column_name AS child_col, " +
" r.table_name AS parent_table, r.column_name AS parent_col, " +
" c.constraint_name " +
"FROM user_constraints c " +
"JOIN user_cons_columns a ON c.constraint_name = a.constraint_name " +
"JOIN user_cons_columns r ON c.r_constraint_name = r.constraint_name " +
" AND a.position = r.position " +
"WHERE c.constraint_type = 'R' " +
"AND UPPER(a.table_name) IN (" + inList + ") " +
"ORDER BY a.table_name, c.constraint_name, a.position"
};
}
if (dbType === 'postgres' || dbType === 'postgresql') {
return {
cols:
"SELECT c.table_name AS \"TABLE_NAME\", c.column_name AS \"COLUMN_NAME\", " +
" c.data_type AS \"DATA_TYPE\", c.character_maximum_length AS \"DATA_LENGTH\", " +
" c.numeric_precision AS \"DATA_PRECISION\", c.numeric_scale AS \"DATA_SCALE\", " +
" c.is_nullable AS \"NULLABLE\", c.ordinal_position AS \"COLUMN_ID\", " +
" CASE WHEN pk.column_name IS NOT NULL THEN 'Y' ELSE 'N' END AS \"IS_PK\" " +
"FROM information_schema.columns c " +
"LEFT JOIN ( " +
" SELECT kcu.table_name, kcu.column_name " +
" FROM information_schema.table_constraints tc " +
" JOIN information_schema.key_column_usage kcu USING (constraint_name) " +
" WHERE tc.constraint_type = 'PRIMARY KEY' " +
") pk ON pk.table_name = c.table_name AND pk.column_name = c.column_name " +
"WHERE c.table_schema = current_schema() " +
"AND UPPER(c.table_name) IN (" + inList + ") " +
"ORDER BY c.table_name, c.ordinal_position",
// ★テスター指摘 No.95: 索引 (PK は indisprimary で除外)。
// ・pg_namespace で current_schema() に限定 (無いと同名テーブルを持つ
// 別スキーマの索引が混入する — cols クエリと非対称だった)
// ・k.ord <= indnkeyatts で INCLUDE 列 (PG11+ の非キー列) を除外
// ・indexprs IS NULL で式索引を除外 (式部分は列名が引けず黙って欠落するため、
// 索引ごと出力しない方が正確)
indexes:
"SELECT t.relname AS \"TABLE_NAME\", ci.relname AS \"INDEX_NAME\", " +
" CASE WHEN ix.indisunique THEN 'Y' ELSE 'N' END AS \"IS_UNIQUE\", " +
" CASE WHEN EXISTS (SELECT 1 FROM pg_constraint uq " +
" WHERE uq.contype = 'u' AND uq.conindid = ix.indexrelid) " +
" THEN 'Y' ELSE 'N' END AS \"IS_UNIQ_CONS\", " +
" a.attname AS \"COLUMN_NAME\" " +
"FROM pg_index ix " +
"JOIN pg_class t ON t.oid = ix.indrelid " +
"JOIN pg_namespace n ON n.oid = t.relnamespace AND n.nspname = current_schema() " +
"JOIN pg_class ci ON ci.oid = ix.indexrelid " +
"JOIN unnest(ix.indkey) WITH ORDINALITY AS k(attnum, ord) " +
" ON k.ord <= ix.indnkeyatts " +
"JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum " +
"WHERE t.relkind = 'r' AND NOT ix.indisprimary " +
"AND ix.indexprs IS NULL " +
"AND UPPER(t.relname) IN (" + inList + ") " +
"ORDER BY t.relname, ci.relname, k.ord",
// コメント系も current_schema() に限定 (索引と同じ別スキーマ混入対策)
comments:
"SELECT c.relname AS \"TABLE_NAME\", d.description AS \"COMMENTS\" " +
"FROM pg_class c " +
"JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = current_schema() " +
"JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = 0 " +
"WHERE c.relkind = 'r' " +
"AND UPPER(c.relname) IN (" + inList + ")",
colComments:
"SELECT c.relname AS \"TABLE_NAME\", a.attname AS \"COLUMN_NAME\", " +
" d.description AS \"COMMENTS\" " +
"FROM pg_class c " +
"JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = current_schema() " +
"JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 " +
"JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = a.attnum " +
"WHERE c.relkind = 'r' " +
"AND UPPER(c.relname) IN (" + inList + ")",
// FK: information_schema.constraint_column_usage は複合 FK で親列との対応が
// 取れず (kcu × ccu がクロス積になる PG の既知の落とし穴)、 列ペアが
// 崩れるため pg_constraint の conkey/confkey を位置対応で unnest する。
fks:
"SELECT tc.relname AS \"CHILD_TABLE\", ca.attname AS \"CHILD_COL\", " +
" tp.relname AS \"PARENT_TABLE\", pa.attname AS \"PARENT_COL\", " +
" cn.conname AS \"CONSTRAINT_NAME\" " +
"FROM pg_constraint cn " +
"JOIN pg_class tc ON tc.oid = cn.conrelid " +
"JOIN pg_namespace n ON n.oid = tc.relnamespace AND n.nspname = current_schema() " +
"JOIN pg_class tp ON tp.oid = cn.confrelid " +
"JOIN unnest(cn.conkey) WITH ORDINALITY AS k(attnum, ord) ON true " +
"JOIN unnest(cn.confkey) WITH ORDINALITY AS fk(attnum, ord) ON fk.ord = k.ord " +
"JOIN pg_attribute ca ON ca.attrelid = tc.oid AND ca.attnum = k.attnum " +
"JOIN pg_attribute pa ON pa.attrelid = tp.oid AND pa.attnum = fk.attnum " +
"WHERE cn.contype = 'f' " +
"AND UPPER(tc.relname) IN (" + inList + ") " +
"ORDER BY tc.relname, cn.conname, k.ord"
};
}
if (dbType === 'mysql') {
// MySQL: information_schema を使用。テーブルコメントは TABLES.TABLE_COMMENT、
// 列コメントは COLUMNS.COLUMN_COMMENT。スキーマは DATABASE() (現在 DB)。
return {
cols:
"SELECT c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE, " +
" c.CHARACTER_MAXIMUM_LENGTH AS DATA_LENGTH, " +
" c.NUMERIC_PRECISION AS DATA_PRECISION, c.NUMERIC_SCALE AS DATA_SCALE, " +
" c.IS_NULLABLE AS NULLABLE, c.ORDINAL_POSITION AS COLUMN_ID, " +
" CASE WHEN c.COLUMN_KEY = 'PRI' THEN 'Y' ELSE 'N' END AS IS_PK " +
"FROM information_schema.COLUMNS c " +
"WHERE c.TABLE_SCHEMA = DATABASE() " +
"AND UPPER(c.TABLE_NAME) IN (" + inList + ") " +
"ORDER BY c.TABLE_NAME, c.ORDINAL_POSITION",
// ★テスター指摘 No.95: 索引 (PRIMARY は除外)。
// ・COLUMN_NAME IS NOT NULL: MySQL 8 の関数索引は列名が NULL になり
// 空文字が混ざった歪んだカラムリストになるため除外
// ・INDEX_TYPE: FULLTEXT / SPATIAL を通常索引として出さない
indexes:
"SELECT s.TABLE_NAME, s.INDEX_NAME, " +
" CASE WHEN s.NON_UNIQUE = 0 THEN 'Y' ELSE 'N' END AS IS_UNIQUE, " +
// MySQL はユニーク制約 = ユニーク索引で別概念が無い (常に索引扱い = uniq 1)
" 'N' AS IS_UNIQ_CONS, " +
" s.COLUMN_NAME " +
"FROM information_schema.STATISTICS s " +
"WHERE s.TABLE_SCHEMA = DATABASE() " +
"AND UPPER(s.TABLE_NAME) IN (" + inList + ") " +
"AND s.INDEX_NAME <> 'PRIMARY' " +
"AND s.COLUMN_NAME IS NOT NULL " +
"AND s.INDEX_TYPE IN ('BTREE','HASH') " +
"ORDER BY s.TABLE_NAME, s.INDEX_NAME, s.SEQ_IN_INDEX",
comments:
"SELECT TABLE_NAME, TABLE_COMMENT AS COMMENTS " +
"FROM information_schema.TABLES " +
"WHERE TABLE_SCHEMA = DATABASE() " +
"AND UPPER(TABLE_NAME) IN (" + inList + ")",
colComments:
"SELECT TABLE_NAME, COLUMN_NAME, COLUMN_COMMENT AS COMMENTS " +
"FROM information_schema.COLUMNS " +
"WHERE TABLE_SCHEMA = DATABASE() " +
"AND UPPER(TABLE_NAME) IN (" + inList + ") " +
"AND COLUMN_COMMENT <> ''",
fks:
"SELECT kcu.TABLE_NAME AS CHILD_TABLE, kcu.COLUMN_NAME AS CHILD_COL, " +
" kcu.REFERENCED_TABLE_NAME AS PARENT_TABLE, " +
" kcu.REFERENCED_COLUMN_NAME AS PARENT_COL, " +
" kcu.CONSTRAINT_NAME " +
"FROM information_schema.KEY_COLUMN_USAGE kcu " +
"WHERE kcu.TABLE_SCHEMA = DATABASE() " +
"AND kcu.REFERENCED_TABLE_NAME IS NOT NULL " +
"AND UPPER(kcu.TABLE_NAME) IN (" + inList + ") " +
"ORDER BY kcu.TABLE_NAME, kcu.CONSTRAINT_NAME, kcu.ORDINAL_POSITION"
};
}
if (dbType === 'sqlserver') {
// SQL Server: sys.* + sys.extended_properties (MS_Description) でコメント
return {
cols:
// 桁数 (DATA_LENGTH): sys.columns.max_length は バイト長。
// ・nchar/nvarchar は 2 バイト/文字 なので /2 して文字数に
// ・ntext/text/image/xml (LOB) と max(-1) は固定桁数が無いので NULL
// ・それ以外 (char/varchar/binary 等) は max_length をそのまま
"SELECT t.name AS TABLE_NAME, c.name AS COLUMN_NAME, " +
" TYPE_NAME(c.user_type_id) AS DATA_TYPE, " +
" CASE WHEN c.max_length = -1 THEN NULL " +
" WHEN TYPE_NAME(c.user_type_id) IN ('ntext','text','image','xml') THEN NULL " +
" WHEN TYPE_NAME(c.user_type_id) IN ('nchar','nvarchar') THEN c.max_length / 2 " +
" ELSE c.max_length END AS DATA_LENGTH, " +
" c.precision AS DATA_PRECISION, c.scale AS DATA_SCALE, " +
" CASE WHEN c.is_nullable = 1 THEN 'Y' ELSE 'N' END AS NULLABLE, " +
" c.column_id AS COLUMN_ID, " +
" CASE WHEN EXISTS ( " +
" SELECT 1 FROM sys.index_columns ic " +
" JOIN sys.indexes i ON i.object_id = ic.object_id AND i.index_id = ic.index_id " +
" WHERE ic.object_id = c.object_id AND ic.column_id = c.column_id AND i.is_primary_key = 1 " +
" ) THEN 'Y' ELSE 'N' END AS IS_PK " +
"FROM sys.columns c " +
"JOIN sys.tables t ON t.object_id = c.object_id " +
"WHERE UPPER(t.name) IN (" + inList + ") " +
"ORDER BY t.name, c.column_id",
// ★テスター指摘 No.95: 索引 (PK 索引・ヒープ・自動統計は除外)。
// type IN (1,2) = clustered/nonclustered のみ (XML/spatial 等は列表現が
// 別物のため除外)。 無効化 (is_disabled) / 仮想 (hypothetical) も出さない。
indexes:
"SELECT t.name AS TABLE_NAME, i.name AS INDEX_NAME, " +
" CASE WHEN i.is_unique = 1 THEN 'Y' ELSE 'N' END AS IS_UNIQUE, " +
" CASE WHEN i.is_unique_constraint = 1 THEN 'Y' ELSE 'N' END AS IS_UNIQ_CONS, " +
" c.name AS COLUMN_NAME " +
"FROM sys.indexes i " +
"JOIN sys.tables t ON t.object_id = i.object_id " +
"JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id " +
"JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id " +
"WHERE UPPER(t.name) IN (" + inList + ") " +
"AND i.is_primary_key = 0 AND i.type IN (1, 2) AND i.name IS NOT NULL " +
"AND i.is_disabled = 0 AND i.is_hypothetical = 0 AND ic.key_ordinal > 0 " +
"ORDER BY t.name, i.name, ic.key_ordinal",
comments:
"SELECT t.name AS TABLE_NAME, CAST(ep.value AS NVARCHAR(MAX)) AS COMMENTS " +
"FROM sys.tables t " +
"LEFT JOIN sys.extended_properties ep ON ep.major_id = t.object_id " +
" AND ep.minor_id = 0 AND ep.name = 'MS_Description' " +
"WHERE UPPER(t.name) IN (" + inList + ") AND ep.value IS NOT NULL",
colComments:
"SELECT t.name AS TABLE_NAME, c.name AS COLUMN_NAME, " +
" CAST(ep.value AS NVARCHAR(MAX)) AS COMMENTS " +
"FROM sys.tables t " +
"JOIN sys.columns c ON c.object_id = t.object_id " +
"JOIN sys.extended_properties ep ON ep.major_id = t.object_id " +
" AND ep.minor_id = c.column_id AND ep.name = 'MS_Description' " +
"WHERE UPPER(t.name) IN (" + inList + ")",
fks:
"SELECT tc.name AS CHILD_TABLE, cc.name AS CHILD_COL, " +
" tp.name AS PARENT_TABLE, cp.name AS PARENT_COL, " +
" fk.name AS CONSTRAINT_NAME " +
"FROM sys.foreign_keys fk " +
"JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id " +
"JOIN sys.tables tc ON tc.object_id = fkc.parent_object_id " +
"JOIN sys.columns cc ON cc.object_id = fkc.parent_object_id AND cc.column_id = fkc.parent_column_id " +
"JOIN sys.tables tp ON tp.object_id = fkc.referenced_object_id " +
"JOIN sys.columns cp ON cp.object_id = fkc.referenced_object_id AND cp.column_id = fkc.referenced_column_id " +
"WHERE UPPER(tc.name) IN (" + inList + ") " +
"ORDER BY tc.name, fk.name, fkc.constraint_column_id"
};
}
if (dbType === 'cdata') {
// CData JDBC (Salesforce / REST / Excel / SharePoint / 200+ ドライバ群)
// 全ドライバ共通の SYS カタログ:
// - sys_tables: TableName / TableType / Description
// - sys_tablecolumns: TableName / ColumnName / DataTypeName / Length /
// NumericPrecision / NumericScale / IsKey / IsNullable /
// Description / Ordinal / IsHidden / IsReadOnly
// - sys_foreignkeys: PrimaryKeyTable / PrimaryKeyColumn / ForeignKeyTable /
// ForeignKeyColumn / ForeignKeyName / KeySeq
// テーブル名は ソース上の case を保持 (Salesforce: 'Account' / REST: 任意)。
// UPPER() による IN 句で 大小区別なくマッチ可能。
// IsNullable / IsKey は boolean (true/false or 1/0) のため CASE で 'Y'/'N' に正規化。
// IsHidden 列は除外 (内部用途の カラム)。
// exact-match (元 case) を優先し、 無ければ UPPER 比較 (低速) にフォールバック。
// _fetchErMeta 側で exact 0 件時に inListExact=null で再呼出しされる。
var cdT = inListExact ? ("TableName IN (" + inListExact + ")")
: ("UPPER(TableName) IN (" + inList + ")");
var cdTc = inListExact ? ("c.TableName IN (" + inListExact + ")")
: ("UPPER(c.TableName) IN (" + inList + ")");
var cdFk = inListExact ? ("ForeignKeyTable IN (" + inListExact + ")")
: ("UPPER(ForeignKeyTable) IN (" + inList + ")");
// FK クエリ: sys_foreignkeys のスキーマは 2 系統ある:
// legacy: ForeignKeyTable/ForeignKeyColumn/PrimaryKeyTable/PrimaryKeyColumn (Google Sheets 等)
// ref: TableName/ColumnName/ReferencedTableName/ReferencedColumnName (Salesforce 25.0 で確認)
// 未知列を含むクエリは CData が全メタデータ列挙に落ちて失敗まで数分かかるため、
// サブドライバ名が分かる場合は正しい側を本命にし、 もう一方をフォールバックに回す。
var _cdFkLegacy =
"SELECT ForeignKeyTable AS CHILD_TABLE, ForeignKeyColumn AS CHILD_COL, " +
" PrimaryKeyTable AS PARENT_TABLE, PrimaryKeyColumn AS PARENT_COL, " +
" ForeignKeyName AS CONSTRAINT_NAME " +
"FROM sys_foreignkeys " +
"WHERE " + cdFk + " " +
"ORDER BY ForeignKeyTable, ForeignKeyName, KeySeq";
var _cdFkRef =
"SELECT TableName AS CHILD_TABLE, ColumnName AS CHILD_COL, " +
" ReferencedTableName AS PARENT_TABLE, ReferencedColumnName AS PARENT_COL, " +
" ForeignKeyName AS CONSTRAINT_NAME " +
"FROM sys_foreignkeys " +
"WHERE " + cdT + " " +
"ORDER BY TableName, ForeignKeyName";
return {
cols:
// 注: ColumnLabel 列は SELECT しない。 Salesforce ドライバ (25.0) には
// 存在せず、 未知列を含むクエリは CData が全メタデータ列挙に落ちて
// 失敗までに数分かかる。 ラベル相当は Description の定型文
// ("'X' ラベルはこのフィールドに一致します。") から抽出する
// (_cdataCommentToLabel)。 Google Sheets 等の ColumnLabel は
// ColumnName と同値のため SELECT する価値が無い。
// ★ 性能: 列コメント (Description) を cols に統合し、 別途 colComments で
// sys_tablecolumns を 2 回スキャンしていたのを 1 回に削減 (colComments=null)。
"SELECT c.TableName AS TABLE_NAME, c.ColumnName AS COLUMN_NAME, " +
" c.DataTypeName AS DATA_TYPE, c.Length AS DATA_LENGTH, " +
" c.NumericPrecision AS DATA_PRECISION, c.NumericScale AS DATA_SCALE, " +
" CASE WHEN c.IsNullable = true THEN 'Y' ELSE 'N' END AS NULLABLE, " +
" c.Ordinal AS COLUMN_ID, " +
" CASE WHEN c.IsKey = true THEN 'Y' ELSE 'N' END AS IS_PK, " +
" c.Description AS COL_COMMENT " +
"FROM sys_tablecolumns c " +
"WHERE " + cdTc + " " +
"AND (c.IsHidden IS NULL OR c.IsHidden = false) " +
"ORDER BY c.TableName, c.Ordinal",
comments:
// CData boilerplate ('autogenerated.' / 'No description.') は除外
"SELECT TableName AS TABLE_NAME, Description AS COMMENTS " +
"FROM sys_tables " +
"WHERE " + cdT + " " +
"AND Description IS NOT NULL " +
"AND Description != 'autogenerated.' AND Description != 'autogenerated' " +
"AND Description != 'No description.' AND Description != 'No description'",
// colComments は cols に統合済 (sys_tablecolumns の再スキャンを廃止して高速化)
colComments: null,
fks: (cdataSub === 'salesforce') ? _cdFkRef : _cdFkLegacy,
fksFallback: (cdataSub === 'salesforce') ? _cdFkLegacy : _cdFkRef
};
}
if (dbType === 'db2') {
// DB2: SYSCAT.* カタログビュー。 既定スキーマは CURRENT SCHEMA。
// - SYSCAT.COLUMNS: TABNAME / COLNAME / TYPENAME / LENGTH / SCALE / NULLS
// (NULLS='Y' が NULL 許可) / COLNO / KEYSEQ (>0 が PK) / REMARKS
// - SYSCAT.TABLES: TABNAME / REMARKS (テーブルコメント)
// - SYSCAT.REFERENCES + SYSCAT.KEYCOLUSE: FK 関係 (子 KEYCOLUSE と親 KEYCOLUSE を
// COLSEQ で対応付けて 1 列ずつ展開)
return {
cols:
"SELECT c.TABNAME AS TABLE_NAME, c.COLNAME AS COLUMN_NAME, " +
" c.TYPENAME AS DATA_TYPE, c.LENGTH AS DATA_LENGTH, " +
" c.LENGTH AS DATA_PRECISION, c.SCALE AS DATA_SCALE, " +
" c.NULLS AS NULLABLE, c.COLNO AS COLUMN_ID, " +
" CASE WHEN c.KEYSEQ > 0 THEN 'Y' ELSE 'N' END AS IS_PK " +
"FROM SYSCAT.COLUMNS c " +
"WHERE c.TABSCHEMA = CURRENT SCHEMA " +
"AND UPPER(c.TABNAME) IN (" + inList + ") " +
"ORDER BY c.TABNAME, c.COLNO",
comments:
"SELECT TABNAME AS TABLE_NAME, REMARKS AS COMMENTS " +
"FROM SYSCAT.TABLES " +
"WHERE TABSCHEMA = CURRENT SCHEMA " +
"AND UPPER(TABNAME) IN (" + inList + ") AND REMARKS IS NOT NULL",
colComments:
"SELECT TABNAME AS TABLE_NAME, COLNAME AS COLUMN_NAME, REMARKS AS COMMENTS " +
"FROM SYSCAT.COLUMNS " +
"WHERE TABSCHEMA = CURRENT SCHEMA " +
"AND UPPER(TABNAME) IN (" + inList + ") AND REMARKS IS NOT NULL",
fks:
"SELECT r.TABNAME AS CHILD_TABLE, kc.COLNAME AS CHILD_COL, " +
" r.REFTABNAME AS PARENT_TABLE, kp.COLNAME AS PARENT_COL, " +
" r.CONSTNAME AS CONSTRAINT_NAME " +
"FROM SYSCAT.REFERENCES r " +
"JOIN SYSCAT.KEYCOLUSE kc ON kc.CONSTNAME = r.CONSTNAME " +
" AND kc.TABSCHEMA = r.TABSCHEMA " +
" AND kc.TABNAME = r.TABNAME " +
"JOIN SYSCAT.KEYCOLUSE kp ON kp.CONSTNAME = r.REFKEYNAME " +
" AND kp.TABSCHEMA = r.REFTABSCHEMA " +
" AND kp.TABNAME = r.REFTABNAME " +
" AND kp.COLSEQ = kc.COLSEQ " +
"WHERE r.TABSCHEMA = CURRENT SCHEMA " +
"AND UPPER(r.TABNAME) IN (" + inList + ") " +
"ORDER BY r.TABNAME, r.CONSTNAME, kc.COLSEQ"
};
}
throw new Error('Unsupported dbType: ' + dbType);
}
// ============================================================
// DDL (CREATE TABLE + ALTER TABLE ADD CONSTRAINT) 生成
// ============================================================
// draw.io / MySQL Workbench / A5:SQL Mk-2 / DBeaver 等 ほぼ全ての ER 図ツールで
// 「DDL リバース」入力として使える業界標準形式。 副次的にバックアップ・移植にも使える。
// FK 行 (列単位) → 制約単位のグルーピング (複合 FK) は TFE (Ver1.0.7 に分離)
function _groupFks(fks) { return _tfe().groupFks(fks); }
function _erToDdl(meta, dbType) {
var s = '-- Generated by TLN_FUNC_DOC_ER_DIAGRAM_COMMON (dbType=' + dbType + ')\n';
s += '-- ' + new Date() + '\n\n';
// CREATE TABLE
for (var ti = 0; ti < meta.tables.length; ti++) {
var t = meta.tables[ti];
s += '-- ============================================================\n';
s += '-- ' + t.name + (t.comment ? ' (' + t.comment + ')' : '') + '\n';
s += '-- ============================================================\n';
s += 'CREATE TABLE ' + t.name + ' (\n';
var pkCols = [];
for (var ci = 0; ci < t.cols.length; ci++) {
var c = t.cols[ci];
s += ' ' + c.name + ' ' + _ddlType(c, dbType);
if (!c.nullable) s += ' NOT NULL';
s += (ci < t.cols.length - 1) ? ',\n' : '\n';
if (c.isPk) pkCols.push(c.name);
}
s += ');\n';
if (pkCols.length > 0) {
s += 'ALTER TABLE ' + t.name +
' ADD CONSTRAINT PK_' + t.name +
' PRIMARY KEY (' + pkCols.join(', ') + ');\n';
}
// テーブルコメント (Oracle / PostgreSQL ともに COMMENT ON TABLE 構文)
if (t.comment) {
s += "COMMENT ON TABLE " + t.name + " IS '" + _ddlEsc(t.comment) + "';\n";
}
// 列コメント (= 論理名相当)
for (var ck = 0; ck < t.cols.length; ck++) {
var cc = t.cols[ck];
if (cc.comment) {
s += "COMMENT ON COLUMN " + t.name + "." + cc.name + " IS '" + _ddlEsc(cc.comment) + "';\n";
}
}
// ★テスター指摘 No.95 拡張: 索引 (非 PK)。 a5er の IndexInfo と対で DDL にも出力
// (CREATE [UNIQUE] INDEX は 4 方言共通構文)
var _dIdxs = t.indexes || [];
for (var dxi = 0; dxi < _dIdxs.length; dxi++) {
var _dx = _dIdxs[dxi];
if (_dx.uniqCons) {
// ユニーク制約バック: CREATE UNIQUE INDEX だと再生成時に制約が索引に
// 化けるため、 制約として出力する (a5er の uniq=2 と対)
s += 'ALTER TABLE ' + t.name + ' ADD CONSTRAINT ' + _dx.name +
' UNIQUE (' + _dx.cols.join(', ') + ');\n';
} else {
s += 'CREATE ' + (_dx.unique ? 'UNIQUE ' : '') + 'INDEX ' + _dx.name +
' ON ' + t.name + ' (' + _dx.cols.join(', ') + ');\n';
}
}
s += '\n';
}
// FK 制約 (複合 FK は 1 本の ALTER に列を並べる — _groupFks)
var _fkGroups = _groupFks(meta.fks);
if (_fkGroups.length > 0) {
s += '-- ============================================================\n';
s += '-- Foreign Key Constraints\n';
s += '-- ============================================================\n';
for (var fi = 0; fi < _fkGroups.length; fi++) {
var f = _fkGroups[fi];
s += 'ALTER TABLE ' + f.childTable +
' ADD CONSTRAINT ' + (f.name || ('FK_' + f.childTable + '_' + (fi + 1))) +
' FOREIGN KEY (' + f.childCols.join(', ') + ')' +
' REFERENCES ' + f.parentTable + ' (' + f.parentCols.join(', ') + ');\n';
}
}
return s;
}
function _ddlType(c, dbType) {
var t = String(c.type || '').toUpperCase();
if ((t === 'NUMBER' || t === 'NUMERIC' || t === 'DECIMAL')) {
if (c.prec) {
return t + '(' + c.prec + (c.scale && c.scale !== '0' ? ',' + c.scale : '') + ')';
}
return t;
}
if ((t.indexOf('CHAR') >= 0 || t.indexOf('VARCHAR') >= 0) && c.len && c.len !== '0') {
return t + '(' + c.len + ')';
}
return t || 'VARCHAR2(255)';
}
function _ddlEsc(s) {
return String(s || '').replace(/'/g, "''");
}
// .a5er 生成 (物理 DB のメタ → A5:SQL Mk-2) は TFE (Ver1.0.7 に分離)
function _erToA5er(meta) { return _tfe().erToA5er(meta); }
// ============================================================
// ZIP 出力 (Java util.zip)
// ============================================================
// entries: [{name: 'a.html', content: 'string'}, {name: 'b.drawio', content: byte[]}]
// content は string (= UTF-8 でエンコード) または Java byte[] (= そのまま書き込み)
// バイナリファイル (.drawio 圧縮 XML / 画像 等) は byte[] で渡すこと
// 戻り値: byte[] (Java)
TFC.zip = function (entries) {
var baos = new ByteArrayOutputStream();
var zos = new ZipOutputStream(baos, Charset.forName('UTF-8'));
try {
for (var i = 0; i < entries.length; i++) {
var e = entries[i];
zos.putNextEntry(new ZipEntry(e.name));
var bytes;
// Java byte[] (= getClass().getName() === '[B') ならそのまま使う
if (e.content && typeof e.content === 'object' &&
e.content.getClass && e.content.getClass().getName() === '[B') {
bytes = e.content;
} else {
bytes = new JString(e.content).getBytes(Charset.forName('UTF-8'));
}
zos.write(bytes, 0, bytes.length);
zos.closeEntry();
}
} finally {
zos.close();
}
return baos.toByteArray();
};
// ============================================================
// サーバ側出力 (Ver1.0.1)
// ============================================================
// ZIP と同じ成果物一式を サーバ上の {ベース}/{yyyyMMdd_HHmmss}/ に展開し、 {ベース}/index.html
// (出力履歴の一覧) を再生成する。 ZIP ダウンロードとの切替は 汎用CD TLN_FUNC_DOC_SERVER_OUT
// (SETUP が 0 行時に seed。 環境設定なので出荷 CSV には含めない — filter_product_pkg_export.py):
// MODE : 2=サーバのみ (SETUP の既定、 2026-09-11) / 1=ZIP + サーバ / 0=ZIP ダウンロードのみ
// (汎用CD が無い・値が不正なときは 0 = 従来どおり ZIP)
// PATH : 物理ベースフォルダ (空または空白のみ = THUMBNAIL_UPLOAD_PATH の表示値 + /TLN_FUNC_DOC)
// URL : 一覧の URL 接頭辞 (空または空白のみ = THUMBNAIL_UPLOAD_PATH の表示2 + /TLN_FUNC_DOC。
// TALON の添付ファイル URL と同じ規則: 先頭 '/' あり = ルート相対 (docroot 配信) /
// 無し = /Talon コンテキスト相対 (alternatedocroot 配信)。 クライアント側で解決する)
// KEEP : 保持世代数 (空/0 = 無制限。 超過分は古い順に削除)
// 一覧は 各世代フォルダの manifest.json を走査して毎回作り直す (文字列挿入ではない =
// 同時実行・手動削除に強い)。 index.html は一時ファイルに書いてから置換する。
// ★ファイル名に日本語を含むため、 Linux では JVM の sun.jnu.encoding が UTF-8 であること
// (Payara 公式イメージは LANG=en_US.UTF-8 で満たす)。
var _NioFiles = Java.type('java.nio.file.Files');
var _NioPaths = Java.type('java.nio.file.Paths');
var _NioCopyOpt = Java.type('java.nio.file.StandardCopyOption');
var _JComparator = Java.type('java.util.Comparator');
TFC.SERVER_OUT_SIKIBETU = 'TLN_FUNC_DOC_SERVER_OUT';
// 既定フォルダ名 = 設計書出力の機能 ID。 TALON 側で THUMBNAIL 配信サーブレット (認可付き) が入ったとき
// 「最初のフォルダ名が機能 ID ならその機能の権限で判定」 の規則に乗るため (2026-09-11 決定)。
// Ver1.0.1 のテスター版で使っていた 'commonweal' は初回出力時にフォルダごと改名して履歴を引き継ぐ。
TFC.SERVER_OUT_SUBDIR = 'TLN_FUNC_DOC';
TFC.SERVER_OUT_SUBDIR_LEGACY = 'commonweal';
TFC.SERVER_OUT_MANIFEST = 'manifest.json';
TFC.SERVER_OUT_INDEX_JSON = 'index.json'; // 2026-10-14: 世代の機械可読一覧 (差分設計書 Compare.html が ../index.json で読む)
// string → UTF-8 bytes / Java byte[] → そのまま (TFC.zip と同じ規約)
function _contentToBytes(content) {
if (content && typeof content === 'object' &&
content.getClass && content.getClass().getName() === '[B') {
return content;
}
return new JString(content == null ? '' : String(content)).getBytes(Charset.forName('UTF-8'));
}
// 前後の空白 (全角スペース含む) を除く。 ★汎用コードマスタの表示値は必須入力で空に戻せないため、
// 半角空白 1 文字を「未設定」として受け付ける (テスター指摘 No.147。 KB セットアップガイド §5 に明記)
function _trimS(v) { return TFC.s(v).replace(/^[\s\u3000]+|[\s\u3000]+$/g, ''); }
// 汎用CD TLN_FUNC_DOC_SERVER_OUT + THUMBNAIL_UPLOAD_PATH から設定を解決する。
// 戻り値: { mode, basePath, urlBase, keep, thumbPath, thumbTop, error }
// 汎用CD 未整備 (SETUP 未実行) や取得失敗は mode=0 (= 従来どおり ZIP のみ)。
TFC.serverOutConfig = function () {
var cfg = { mode: 0, basePath: '', urlBase: '', keep: 0, thumbPath: '', thumbTop: '', error: '' };
try {
var rows = TFC.selectPS(
'SELECT KEY_CODE, DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE = ?',
[TFC.SERVER_OUT_SIKIBETU]);
var vals = {};
for (var i = 0; i < rows.length; i++) {
vals[_trimS(rows[i]['KEY_CODE']).toUpperCase()] = _trimS(rows[i]['DSP1']);
}
var m = parseInt(vals['MODE'], 10);
cfg.mode = (m === 1 || m === 2) ? m : 0;
var k = parseInt(vals['KEEP'], 10);
cfg.keep = (k > 0) ? k : 0;
cfg.basePath = vals['PATH'] || '';
cfg.urlBase = vals['URL'] || '';
} catch (e) {
cfg.error = String(e);
// ★握りつぶさない: 設定が読めなかった理由をログに残す (ZIP ダウンロードへ黙って戻る事故の切り分け用)
try { TALON.getLogger().writeWarn('[TFC] server out config failed (ZIP only): ' + e); } catch (ig) {}
}
if (cfg.mode === 0) return cfg;
try {
var tp = TFC.selectPS(
"SELECT DSP1, DSP2 FROM TLN_M_HANYO_CODE_MAIN " +
"WHERE SIKIBETU_CODE = 'TLN_GENERAL' AND KEY_CODE = 'THUMBNAIL_UPLOAD_PATH'", []);
if (tp.length > 0) {
cfg.thumbPath = _trimS(tp[0]['DSP1']);
cfg.thumbTop = _trimS(tp[0]['DSP2']);
}
} catch (e2) { /* 取得不能なら PATH/URL の明示設定だけを使う */ }
var pathExplicit = !!cfg.basePath; // 汎用CD PATH で出力先を上書きしているか
if (!cfg.basePath && cfg.thumbPath) {
cfg.basePath = cfg.thumbPath.replace(/[\\\/]+$/, '') + '/' + TFC.SERVER_OUT_SUBDIR;
}
// URL は PATH を上書きしていないときだけ THUMBNAIL の規則から導く。 PATH を別の場所にした場合は
// その場所を配信する URL を利用者が設定する (空ならリンクを出さず、 完了メッセージには世代フォルダ名だけを出す)。
// 旧実装は PATH に関係なく THUMBNAIL 配下の URL を組み立てていたため、 開けないリンクになっていた (2026-09-11)。
if (!cfg.urlBase && !pathExplicit) {
var top = cfg.thumbTop.replace(/\\/g, '/').replace(/\/+$/, '');
if (top) cfg.urlBase = top + '/' + TFC.SERVER_OUT_SUBDIR;
}
return cfg;
};
// ★2026-10-08 (テスター要望「設計書の一覧を出力時以外にも」): サーバ保存の一覧 (index.html) への URL を、 開く場所に合わせた相対形で返す。
// kind = 'menu' : TALON のメニュー行 (TLN_M_FUNCTION.APP_URL)。 メニューは faces/ を前置して開く (実測 2026-10-08) ので /{ctx}/faces/ からの相対。
// 絶対 URL (http) は前置されて壊れるので null (= メニュー行を作らない)
// kind = 'screen' : 画面の他画面呼出 (URL 指定) = /{ctx}/faces/TALON/APPLICATION/GENERALFREE/ からの相対。 絶対 URL はそのまま
// null = 置けない (サーバ保存が ZIP のみ / URL が空)。 純関数 = tests/test_server_out_index_url.py
function _serverOutIndexUrlFrom(cfg, kind) {
if (!cfg || !cfg.mode) return null;
var base = String(cfg.urlBase || '').replace(/\\/g, '/').replace(/\/+$/, '');
if (!base) return null;
var idx = base + '/index.html';
if (/^https?:\/\//i.test(idx)) return (kind === 'menu') ? null : idx;
if (idx.charAt(0) === '/') return (kind === 'menu') ? '../..' + idx : idx;
return (kind === 'menu') ? '../' + idx : '../../../../' + idx;
}
TFC.serverOutIndexUrl = function (kind) { return _serverOutIndexUrlFrom(TFC.serverOutConfig(), kind); };
// {ベース} 直下の世代フォルダ (manifest.json を持つもの) を新しい順に読む
function _serverOutManifestList(base) {
var list = [];
if (!_NioFiles.isDirectory(base)) return list;
var ds = _NioFiles.newDirectoryStream(base);
try {
var it = ds.iterator();
while (it.hasNext()) {
var p = it.next();
if (!_NioFiles.isDirectory(p)) continue;
var mf = p.resolve(TFC.SERVER_OUT_MANIFEST);
if (!_NioFiles.isRegularFile(mf)) continue;
try {
var m = JSON.parse(String(new JString(_NioFiles.readAllBytes(mf), 'UTF-8')));
m.dir = String(p.getFileName());
list.push(m);
} catch (eM) { /* 壊れた manifest は一覧から外す */ }
}
} finally { ds.close(); }
list.sort(function (a, b) { return a.dir < b.dir ? 1 : (a.dir > b.dir ? -1 : 0); });
return list;
}
function _serverOutDeleteTree(p) {
var st = _NioFiles.walk(p);
try {
var it = st.sorted(_JComparator.reverseOrder()).iterator();
while (it.hasNext()) _NioFiles.deleteIfExists(it.next());
} finally { st.close(); }
}
// 保持世代数を超えた古い世代を削除する (manifest.json を持つフォルダだけが対象)
function _serverOutPrune(base, keep) {
if (!(keep > 0)) return 0;
var list = _serverOutManifestList(base);
var removed = 0;
for (var i = keep; i < list.length; i++) {
try {
_serverOutDeleteTree(base.resolve(list[i].dir));
removed++;
} catch (eD) {
try { TALON.getLogger().writeWarn('[TFC] server out prune failed: ' + list[i].dir + ' ' + eD); } catch (ig) {}
}
}
return removed;
}
function _serverOutWriteAtomic(path, bytes) {
var tmp = path.resolveSibling(String(path.getFileName()) + '.tmp');
_NioFiles.write(tmp, bytes);
try {
_NioFiles.move(tmp, path, _NioCopyOpt.REPLACE_EXISTING, _NioCopyOpt.ATOMIC_MOVE);
} catch (eA) {
_NioFiles.move(tmp, path, _NioCopyOpt.REPLACE_EXISTING);
}
}
// {ベース} フォルダを用意して返す (serverOutWrite / serverOutEnsureIndex 共通)。
// 旧既定フォルダ (commonweal/) が残っていて新フォルダが無ければ、 フォルダごと改名して世代と manifest を
// 引き継ぐ (一覧 index.html は manifest から再生成されるので改名だけで復元する)。 PATH で明示された
// 出力先 (末尾が既定名でない) は対象外。 改名に失敗したら新フォルダで始める (旧フォルダはそのまま残る)。
function _serverOutPrepareBase(cfg) {
var base = _NioPaths.get(cfg.basePath);
if (!_NioFiles.exists(base) && String(base.getFileName()) === TFC.SERVER_OUT_SUBDIR) {
var legacy = base.resolveSibling(TFC.SERVER_OUT_SUBDIR_LEGACY);
if (_NioFiles.isDirectory(legacy)) {
try {
_NioFiles.move(legacy, base);
try { TALON.getLogger().writeInfo('[TFC] server out: renamed legacy folder ' + legacy + ' -> ' + base); } catch (ig1) {}
} catch (eMv) {
try { TALON.getLogger().writeWarn('[TFC] server out: legacy folder rename failed, starting a new folder: ' + eMv); } catch (ig2) {}
}
}
}
_NioFiles.createDirectories(base);
return base;
}
// ★No.313 (2026-10-14): 一覧 (index.html / index.json) を世代の有無にかかわらず作り直す (無ければ空の一覧)。
// 設計書を一度も出力していない環境でメニュー / 画面の [設計書一覧] を開くと 404 になっていた (一覧は最初の出力で作られるため)。
// SETUP の [処理実行] と [メニュー登録] が呼ぶ (冪等。 サーバ保存が ZIP のみ (mode 0) や出力先が未設定なら何もしない)。
// 既にある一覧も manifest から作り直すので、 版上げ後に古い形の一覧 (差分の選択が無い等) が残らない。
TFC.serverOutEnsureIndex = function (lang) {
var cfg = TFC.serverOutConfig();
if (!cfg || !cfg.mode || !cfg.basePath) return { skipped: true, mode: cfg ? cfg.mode : null };
var base = _serverOutPrepareBase(cfg);
var list = _serverOutManifestList(base);
var idxLang = (lang === 'en' || lang === 'ja') ? lang : TFC.uiLang();
_serverOutWriteAtomic(base.resolve('index.html'), _contentToBytes(_serverOutIndexHtml(list, idxLang)));
_serverOutWriteAtomic(base.resolve(TFC.SERVER_OUT_INDEX_JSON), _contentToBytes(_serverOutIndexJson(list)));
return { dir: String(base.toAbsolutePath()), generations: list.length };
};
/**
* 成果物一式をサーバへ展開し、 一覧 index.html を再生成する。
* @param cfg TFC.serverOutConfig() の戻り値 (mode >= 1)
* @param entries ZIP と同じ [{name, content}] (content は string または Java byte[])
* @param manifest {stamp, datetime, user, lang, edition, funcs, conditions, projects, zipName}
* (dir / fileCount / bytes / zipFile / zipBytes はこの関数が補う)
* @param extras 任意。 成果物とは別に世代フォルダへ置くファイル [{name, content}] (例: ZIP 本体。
* 一覧 index.html から「ZIPをダウンロード」でそのまま取得できる)
* @returns {dir, dirName, url, indexUrl, mdZipUrl, fileCount, bytes, removed, generations}
* extras: [{name, content, key?}] — key='mdZip' の要素は manifest.mdZipFile / mdZipBytes に記録する
*/
TFC.serverOutWrite = function (cfg, entries, manifest, extras) {
if (!cfg || !cfg.basePath) {
throw new Error('server out: base path is empty (THUMBNAIL_UPLOAD_PATH or PATH is not set)');
}
var base = _serverOutPrepareBase(cfg);
var dirName = manifest.stamp;
var dir = base.resolve(dirName);
for (var n = 2; _NioFiles.exists(dir) && n < 100; n++) { // 同秒の衝突 (別利用者の同時実行)
dirName = manifest.stamp + '_' + n;
dir = base.resolve(dirName);
}
_NioFiles.createDirectories(dir);
var bytesTotal = 0, fileCount = 0;
for (var i = 0; i < entries.length; i++) {
var e = entries[i];
var rel = String(e.name).replace(/\\/g, '/').replace(/^\/+/, '');
if (!rel || rel.split('/').indexOf('..') >= 0) continue; // 防御: 世代フォルダ外への書込を禁止
var p = dir.resolve(rel);
var parent = p.getParent();
if (parent != null) _NioFiles.createDirectories(parent);
var bytes = _contentToBytes(e.content);
_NioFiles.write(p, bytes);
bytesTotal += bytes.length;
fileCount++;
}
manifest.dir = dirName;
manifest.fileCount = fileCount;
manifest.bytes = bytesTotal;
// 付随ファイル (ZIP 本体など)。 世代フォルダ直下に置き、 KEEP の削除でフォルダごと消える
if (extras && extras.length) {
for (var x = 0; x < extras.length; x++) {
var xn = String(extras[x].name).replace(/[\\/]/g, '_');
if (!xn) continue;
var xb = _contentToBytes(extras[x].content);
_NioFiles.write(dir.resolve(xn), xb);
if (extras[x].key === 'mdZip') { // AI 向け Markdown (meta/) だけの ZIP
manifest.mdZipFile = xn;
manifest.mdZipBytes = xb.length;
} else if (/\.zip$/i.test(xn) && !manifest.zipFile) {
manifest.zipFile = xn;
manifest.zipBytes = xb.length;
}
}
}
_NioFiles.write(dir.resolve(TFC.SERVER_OUT_MANIFEST), _contentToBytes(JSON.stringify(manifest, null, 1)));
var removed = _serverOutPrune(base, cfg.keep);
var list = _serverOutManifestList(base);
// 一覧の静的な既定言語 = この出力の言語 (設計書と同じ)。 閲覧時はブラウザ言語で差し替わる (No.145)
var idxLang = (manifest.lang === 'en' || manifest.lang === 'ja') ? manifest.lang : TFC.uiLang();
_serverOutWriteAtomic(base.resolve('index.html'), _contentToBytes(_serverOutIndexHtml(list, idxLang)));
_serverOutWriteAtomic(base.resolve(TFC.SERVER_OUT_INDEX_JSON), _contentToBytes(_serverOutIndexJson(list))); // 2026-10-14: Compare.html が世代を選ぶための一覧
var urlBase = TFC.s(cfg.urlBase).replace(/\/+$/, '');
return {
dir: String(dir.toAbsolutePath()), dirName: dirName, fileCount: fileCount, bytes: bytesTotal,
url: urlBase ? (urlBase + '/' + dirName + '/index.html') : '',
indexUrl: urlBase ? (urlBase + '/index.html') : '',
mdZipUrl: (urlBase && manifest.mdZipFile) ? (urlBase + '/' + dirName + '/' + manifest.mdZipFile) : '',
removed: removed, generations: list.length
};
};
var _SV_CSS =
"body{font-family:'Segoe UI',Meiryo,sans-serif;background:#f1f5f9;color:#1e293b;margin:0;padding:0 24px 32px;line-height:1.55}" +
".sv-hero{position:relative;background:linear-gradient(135deg,#0369a1,#0891b2);color:#fff;padding:24px 28px;border-radius:8px;margin:18px 0 16px}" +
".sv-lang{position:absolute;top:14px;right:16px;font-size:.85em;white-space:nowrap}" +
".sv-lang a{color:#fff;opacity:.75;text-decoration:none;margin-left:6px;padding:3px 10px;border:1px solid rgba(255,255,255,.6);border-radius:12px}" +
".sv-lang a.on{opacity:1;background:rgba(255,255,255,.22);font-weight:bold}" +
".sv-hero h1{font-size:1.5em;margin:0;font-weight:bold}" +
".sv-hero .sub{margin-top:6px;opacity:.9;font-size:.92em}" +
".sv-count{color:#64748b;font-size:.9em;margin:0 0 10px}" +
".sv-table{border-collapse:collapse;width:100%;background:#fff;border:1px solid #cbd5e1;font-size:.9em}" +
".sv-table th{background:#e2e8f0;text-align:left;padding:8px 10px;border-bottom:1px solid #cbd5e1;white-space:nowrap}" +
".sv-table td{padding:8px 10px;border-bottom:1px solid #e2e8f0;vertical-align:top}" +
".sv-table tr:hover td{background:#f8fafc}" +
".sv-id{color:#94a3b8;font-family:Consolas,monospace;font-size:.85em}" +
".sv-dt{white-space:nowrap;font-family:Consolas,monospace}" +
".sv-funcs,.sv-cond{margin:0;padding-left:1.1em}" +
".sv-cond{color:#334155}" +
".sv-open{display:inline-block;padding:5px 12px;background:#0369a1;color:#fff;border-radius:4px;text-decoration:none;font-weight:bold;white-space:nowrap}" +
".sv-open:hover{background:#075985}" +
".sv-zip{display:inline-block;margin-left:6px;padding:5px 10px;border:1px solid #0369a1;color:#0369a1;border-radius:4px;text-decoration:none;font-weight:bold;white-space:nowrap;background:#fff}" +
".sv-zip:hover{background:#e0f2fe}" +
".sv-meta{color:#94a3b8;font-size:.82em;margin-top:4px;font-family:Consolas,monospace}" +
".sv-empty{color:#64748b}" +
"details summary{cursor:pointer;color:#0369a1}" +
".sv-cmpbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:6px 0 12px;padding:10px 14px;border:1px dashed #94a3b8;border-radius:8px;background:#f8fafc}" +
".sv-cmpbar .sv-cmpt{font-weight:bold}" +
".sv-cmpbar button{font-family:inherit;padding:6px 16px;background:#0369a1;color:#fff;border:none;border-radius:5px;cursor:pointer}" +
".sv-cmpbar button:hover{background:#075985}" +
".sv-cmphelp{color:#64748b;font-size:.88em}" +
".sv-cmpmsg{display:none;color:#b91c1c;font-size:.9em}" +
".sv-cmp{white-space:nowrap}.sv-cmp label{cursor:pointer;margin-right:8px}";
function _svFuncLi(fn, esc) {
fn = fn || {};
return '<li><span class="sv-id">' + esc(fn.id) + '</span> ' + esc(fn.nm) + '</li>';
}
// 一覧の言語切替 (閲覧側のインライン JS)。 優先順: URL の ?lang=ja|en > ブラウザに記憶した切替 > ブラウザの言語
// (en 始まりなら英語、 それ以外は日本語 = TALON 6.2.7+ が利用者の言語を決める規則と同じ)。
// [data-ja]/[data-en] を持つ要素 (<title> 含む) の文言を差し替え、 <html lang> と切替ボタンの選択状態も揃える。
// 単体回帰: tests/test_server_out_index.py が実ソースを DOM スタブで実行する
var _SV_LANG_JS =
"<script>(function(){var KEY='commonweal_sv_lang';" +
"function pick(){var m=/[?&]lang=(ja|en)(?:&|$)/.exec(location.search);if(m)return m[1];" +
"try{var s=localStorage.getItem(KEY);if(s==='ja'||s==='en')return s;}catch(e){}" +
"return ((navigator.language||'').toLowerCase().indexOf('en')===0)?'en':'ja';}" +
"function apply(l){var els=document.querySelectorAll('[data-ja]');" +
"for(var i=0;i<els.length;i++){els[i].textContent=els[i].getAttribute('data-'+l);}" +
"document.documentElement.lang=l;var bs=document.querySelectorAll('.sv-lang a');" +
"for(var j=0;j<bs.length;j++){bs[j].className=(bs[j].getAttribute('data-lang')===l)?'on':'';}}" +
"var bs=document.querySelectorAll('.sv-lang a');" +
"for(var k=0;k<bs.length;k++){bs[k].onclick=function(){var l=this.getAttribute('data-lang');" +
"try{localStorage.setItem(KEY,l);}catch(e){}apply(l);return false;};}" +
"apply(pick());})();</script>";
// 世代の機械可読一覧 index.json (純関数。 manifests は新しい順)。 差分設計書 Compare.html がサーバから開かれたとき ../index.json を読んで
// 2 つの世代を選ばせ、 ../<dir>/<zipFile> を取得して比較する (2026-10-14、 ユーザー依頼)。 条件・プロジェクト等の明細は持たせず、
// 選ぶのに要るもの (日時 / 利用者 / 言語 / 機能の数と名前 / ZIP 名) だけ。 検索条件の値は index.html と同じく載せない
function _serverOutIndexJson(manifests) {
var out = [];
for (var i = 0; i < (manifests || []).length; i++) {
var m = manifests[i] || {}, funcs = m.funcs || [], fl = [];
for (var j = 0; j < funcs.length; j++) fl.push({ id: (funcs[j] || {}).id || '', nm: (funcs[j] || {}).nm || '' });
out.push({ dir: m.dir || '', stamp: m.stamp || '', datetime: m.datetime || '',
user: m.user ? { id: m.user.id || '', name: m.user.name || '' } : null,
lang: m.lang || '', edition: m.edition == null ? null : m.edition,
funcCount: m.funcCount != null ? m.funcCount : funcs.length, funcs: fl,
projects: m.projects || [], zipFile: m.zipFile || '', zipBytes: m.zipBytes || 0, mdZipFile: m.mdZipFile || '' });
}
return JSON.stringify({ product: 'Commonweal', generations: out }, null, 1);
}
// 出力履歴の一覧 HTML (純関数。 manifests は新しい順、 lang は静的な既定言語 = 一覧を再生成した出力の言語)。
// ★一覧は環境で 1 ファイルを全利用者が共有するため、 生成時に言語を 1 つに決めず、 文言を日英対訳
// (data-ja / data-en 属性) で持たせて閲覧時にブラウザ言語で差し替える (_SV_LANG_JS。 右上の切替で手動選択も
// でき、 選択はブラウザに記憶)。 JS 無効時は lang の言語で読める。 同文 (未知の条件キー等) は span を付けない。
// テスター指摘 No.145 (英語環境で設計書は英語なのに一覧が日本語) の対応。 単体回帰: tests/test_server_out_index.py
function _serverOutIndexHtml(manifests, lang) {
lang = (lang === 'en') ? 'en' : 'ja';
var esc = function (v) { return TFC.escapeHtml(TFC.s(v)); };
var escA = function (v) { return TFC.escapeAttr(TFC.s(v)); };
var biRaw = function (ja, en) {
if (ja === en) return esc(ja);
return '<span data-ja="' + escA(ja) + '" data-en="' + escA(en) + '">' + esc(lang === 'en' ? en : ja) + '</span>';
};
var bi = function (key, args) {
return biRaw(args ? TFC.tf(key, 'ja', args) : TFC.t(key, 'ja'),
args ? TFC.tf(key, 'en', args) : TFC.t(key, 'en'));
};
var FUNC_SHOW = 5;
var editionKey = { '1': 'sv.edition1', '2': 'sv.edition2', '3': 'sv.edition3' };
var langKey = { ja: 'sv.lang.ja', en: 'sv.lang.en' };
manifests = manifests || [];
var titleJa = TFC.t('sv.title', 'ja'), titleEn = TFC.t('sv.title', 'en');
var s = '<!DOCTYPE html><html lang="' + lang + '"><head><meta charset="UTF-8">' +
'<meta name="viewport" content="width=device-width,initial-scale=1.0">' +
(TFC.FAVICON_LINK || '') +
'<title data-ja="' + escA(titleJa) + '" data-en="' + escA(titleEn) + '">' +
esc(lang === 'en' ? titleEn : titleJa) + '</title>' +
'<style>' + _SV_CSS + '</style></head><body>' +
'<div class="sv-hero">' +
'<div class="sv-lang">' +
'<a href="#" data-lang="ja"' + (lang === 'ja' ? ' class="on"' : '') + '>' + esc(TFC.t('sv.lang.ja', 'ja')) + '</a>' +
'<a href="#" data-lang="en"' + (lang === 'en' ? ' class="on"' : '') + '>' + esc(TFC.t('sv.lang.en', 'en')) + '</a>' +
'</div>' +
'<h1>' + bi('sv.title') + '</h1>' +
'<div class="sub">' + bi('sv.intro') + '</div></div>' +
'<div class="sv-count">' + bi('sv.count', [manifests.length]) + '</div>';
// 2026-10-14: 2 つの世代を選んで差分設計書 (新しい方の Compare.html?old=&new= を開く。 ZIP の取得と比較は Compare.html がサーバから行う)
var svCmpJs = "<script>(function(){var b=document.getElementById('svCmpRun');if(!b)return;" +
"b.onclick=function(){var o=document.querySelector('input[name=cmpOld]:checked'),n=document.querySelector('input[name=cmpNew]:checked');" +
"var m=document.getElementById('svCmpMsg');if(!o||!n||o.value===n.value){if(m)m.style.display='inline';return;}if(m)m.style.display='none';" +
"var a=o.value,c=n.value,newer=(a>c)?a:c;location.href=newer+'/Compare.html?old='+encodeURIComponent(a)+'&new='+encodeURIComponent(c);};})();</script>";
if (manifests.length >= 2) {
s += '<div class="sv-cmpbar"><span class="sv-cmpt">' + bi('sv.cmp.title') + '</span>' +
'<button type="button" id="svCmpRun">' + bi('sv.cmp.run') + '</button>' +
'<span class="sv-cmphelp">' + bi('sv.cmp.help') + '</span>' +
'<span class="sv-cmpmsg" id="svCmpMsg">' + bi('sv.cmp.need') + '</span></div>';
}
if (manifests.length === 0) {
s += '<p class="sv-empty">' + bi('sv.empty') + '</p>';
} else {
s += '<table class="sv-table"><thead><tr>' +
'<th>' + bi('sv.col.cmp') + '</th>' +
'<th>' + bi('sv.col.datetime') + '</th>' +
'<th>' + bi('sv.col.user') + '</th>' +
'<th>' + bi('sv.col.funcs') + '</th>' +
'<th>' + bi('sv.col.conditions') + '</th>' +
'<th>' + bi('sv.col.lang') + '</th>' +
'<th>' + bi('sv.col.edition') + '</th>' +
'<th>' + bi('sv.col.open') + '</th>' +
'</tr></thead><tbody>';
for (var i = 0; i < manifests.length; i++) {
var m = manifests[i] || {};
var funcs = m.funcs || [];
var u = m.user || {};
// 出力した機能: 先頭 FUNC_SHOW 件 + 残りは details で畳む
var fh = '<div>' + bi('sv.funcCount', [funcs.length]) + '</div><ul class="sv-funcs">';
for (var f = 0; f < funcs.length && f < FUNC_SHOW; f++) fh += _svFuncLi(funcs[f], esc);
fh += '</ul>';
if (funcs.length > FUNC_SHOW) {
fh += '<details><summary>' + bi('sv.funcMore', [funcs.length - FUNC_SHOW]) +
'</summary><ul class="sv-funcs">';
for (var f2 = FUNC_SHOW; f2 < funcs.length; f2++) fh += _svFuncLi(funcs[f2], esc);
fh += '</ul></details>';
}
// 検索条件 (非空のみ) + プロジェクト。 条件キーの訳語は 'cond.' + キー (未知のキーは物理名のまま)
var conds = m.conditions || [];
var ch = '';
for (var c = 0; c < conds.length; c++) {
var ck = TFC.s(conds[c].key).toUpperCase();
var lk = 'cond.' + ck;
var lJa = TFC.t(lk, 'ja'), lEn = TFC.t(lk, 'en');
ch += '<li>' + biRaw(lJa === lk ? ck : lJa, lEn === lk ? ck : lEn) + ': ' + esc(conds[c].value) + '</li>';
}
if (m.projects && m.projects.length) {
ch += '<li>' + bi('sv.project') + ': ' + esc(m.projects.join(', ')) + '</li>';
}
ch = ch ? ('<ul class="sv-cond">' + ch + '</ul>')
: ('<span class="sv-empty">' + bi('sv.noCondition') + '</span>');
var dirAttr = TFC.escapeAttr(TFC.s(m.dir));
s += '<tr>' +
'<td class="sv-cmp"><label><input type="radio" name="cmpOld" value="' + dirAttr + '"> ' + bi('sv.cmp.old') + '</label>' +
'<label><input type="radio" name="cmpNew" value="' + dirAttr + '"> ' + bi('sv.cmp.new') + '</label></td>' +
'<td class="sv-dt">' + esc(m.datetime || m.stamp) + '</td>' +
'<td>' + esc(u.name || u.id) +
((u.id && u.name) ? ' <span class="sv-id">' + esc(u.id) + '</span>' : '') + '</td>' +
'<td>' + fh + '</td>' +
'<td>' + ch + '</td>' +
'<td>' + (langKey[m.lang] ? bi(langKey[m.lang]) : esc(m.lang)) + '</td>' +
'<td>' + (editionKey[String(m.edition)] ? bi(editionKey[String(m.edition)]) : esc(m.edition)) + '</td>' +
'<td><a class="sv-open" href="' + dirAttr + '/index.html">' + bi('sv.open') + '</a>' +
(m.zipFile ? '<a class="sv-zip" href="' + dirAttr + '/' + TFC.escapeAttr(TFC.s(m.zipFile)) + '" download>' +
bi('sv.zip') + '</a>' : '') +
(m.mdZipFile ? '<a class="sv-zip sv-md" href="' + dirAttr + '/' + TFC.escapeAttr(TFC.s(m.mdZipFile)) + '" download>' +
bi('sv.mdZip') + '</a>' : '') +
'<div class="sv-meta">' + esc(m.dir) + ' / ' + bi('sv.files', [m.fileCount || 0]) +
(m.zipFile ? ' / ' + esc(m.zipFile) : (m.zipName ? ' / ' + esc(m.zipName) : '')) + '</div></td>' +
'</tr>';
}
s += '</tbody></table>';
}
s += (manifests.length >= 2 ? svCmpJs : '') + _SV_LANG_JS + '</body></html>';
return s;
}
TFC.serverOutIndexHtml = _serverOutIndexHtml;
TFC.serverOutIndexJson = _serverOutIndexJson;
// ============================================================
// Markdown テンプレート部品
// ============================================================
TFC.mdHeader = function (title) {
return '# ' + (title || '') + '\n\n';
};
TFC.mdSection = function (level, heading, body) {
var hashes = '';
for (var i = 0; i < (level || 2); i++) hashes += '#';
return hashes + ' ' + (heading || '') + '\n\n' + (body || '') + '\n';
};
TFC.mdKvTable = function (rows, lang) {
// rows: [[key, val], ...] / lang: 'ja' or 'en' (省略時は 'ja')
if (!rows || rows.length === 0) return '';
var head = '| ' + TFC.t('th.item', lang) + ' | ' + TFC.t('th.value', lang) + ' |\n|------|----|\n';
var s = head;
for (var i = 0; i < rows.length; i++) {
var k = TFC.escapeMd(rows[i][0]);
var v = TFC.escapeMd(rows[i][1] != null ? String(rows[i][1]) : '');
s += '| ' + k + ' | ' + v + ' |\n';
}
return s + '\n';
};
TFC.mdCodeBlock = function (lang, code) {
return '```' + (lang || '') + '\n' + (code || '') + '\n```\n\n';
};
// セル値を raw 扱い (escapeMd しない) でテーブルに埋め込むためのマーカー。
// inline HTML (<a>...</a> 等) を MD テーブルセルに入れたいときに使う。
TFC.mdRaw = function (s) { return { __mdRaw: true, value: String(s || '') }; };
// 任意列のテーブル: headers=['項目1','項目2',...], rows=[[v,v,...],[v,v,...]]
// セル値は文字列 (escapeMd 適用) または TFC.mdRaw(...) オブジェクト (raw 通過)
TFC.mdTable = function (headers, rows) {
if (!headers || headers.length === 0) return '';
var s = '|';
for (var h = 0; h < headers.length; h++) s += ' ' + TFC.escapeMd(headers[h]) + ' |';
s += '\n|';
for (var d = 0; d < headers.length; d++) s += '------|';
s += '\n';
if (rows) {
for (var r = 0; r < rows.length; r++) {
s += '|';
for (var c = 0; c < rows[r].length; c++) {
var cv = rows[r][c];
var v;
if (cv != null && typeof cv === 'object' && cv.__mdRaw) {
// raw: pipe だけは MD テーブルセル区切りと衝突するためエスケープ
v = String(cv.value).replace(/\|/g, '\\|').replace(/\r?\n/g, '<br>');
} else {
v = (cv != null ? String(cv) : '');
v = TFC.escapeMd(v).replace(/\r?\n/g, '<br>');
}
s += ' ' + v + ' |';
}
s += '\n';
}
}
return s + '\n';
};
// ============================================================
// ユーティリティ
// ============================================================
TFC.s = function (v) {
if (v == null) return '';
var s = String(v);
// NUM 系列の DB エンジン差を正規化:
// Oracle : "1"
// SQL Server / MySQL : "1.000000" (BigDecimal scale が CSV 取込時に保持される)
// → 整数化可能なら "1" に揃える。 比較 (=== '1') が DB 横断で動くようにする。
// 実数値 ("1.5" 等) は変更しない。
if (s.length > 2 && s.indexOf('.') > 0 && /^-?\d+\.0+$/.test(s)) {
return s.replace(/\.0+$/, '');
}
return s;
};
TFC.isEmpty = function (v) { return v == null || String(v).length === 0; };
TFC.coalesce = function () {
for (var i = 0; i < arguments.length; i++) {
if (!TFC.isEmpty(arguments[i])) return arguments[i];
}
return '';
};
// ================================================================
// テーブル参照スキャン (scanTableRefs 一式)
// 2026-07-20 に TLN_FUNC_DOC/update-before.server.js から移設 (EXCL_PICK と共有)。
// 呼出前に TFC.scanConfigure({lang, select, dbType}) で実行文脈を渡す:
// lang : 'ja'|'en' — 出典ラベルの言語 (省略時 'ja')
// select : function(sql, params) — DB アクセサ。省略時 TFC.selectPS。
// 0R100 (検索前 = トランザクション外) では PS が使えないため、
// TFC.scanInlineParams で ? を展開し TFC.selectU で実行するアクセサを
// 渡す (TLN_FUNC_DOC_EXCL_PICK の search-before 参照)
// dbType : proc 本体取得の方言 ('oracle'|'postgres'|'mysql'|'sqlserver'|...)。
// 省略時は接続の productName から検出 (トランザクション文脈が必要)
// scanConfigure は proc ソース等のキャッシュをリセットする (共通 JS はエンジンに
// キャッシュされ得るため、リクエストをまたいだ古いキャッシュを残さない)
// ================================================================
var _scanSel = null;
var _scanLang = 'ja';
var _scanDbTypeOverride = '';
function _scanSizeOf(a) {
if (a == null) return 0;
if (typeof a.size === 'function') return a.size();
return a.length || 0;
}
function _scanSelect(sql, params) {
if (_scanSel) return _scanSel(sql, params);
return TFC.selectPS(sql, params);
}
// テーブル参照スキャンの識別子パターン。
// ・multibyte (日本語等) のテーブル名に対応 (- を識別子文字に含める)
// ・各種クォート対応: キャプチャ 1="..." 2=`...` 3=[...] 4=非クォート
// キーワード regex (FROM/JOIN 等) には他のキャプチャを置かないので、 マッチした
// テーブル名は常に m[1]..m[4] のいずれか (_tblFromMatch で解決)。
// ※ Nashorn は関数内からトップレベル var を参照できないことがあるため、 定数 var で
// はなく関数で返す (呼び出し側がローカル変数に受けて使う)。
function _tblPat() {
return '(?:"([^"]+)"|`([^`]+)`|\\[([^\\]]+)\\]|([A-Za-z_$\\u0080-\\uffff][A-Za-z0-9_$\\u0080-\\uffff]*))';
}
function _tblFromMatch(m) {
return m[1] || m[2] || m[3] || m[4] || '';
}
// SQL テキストからノイズ (コメント / 単一引用符文字列) を除去。
// ・/* ... */ ブロックコメント / -- 行コメント を除去
// ・'...' 文字列リテラルを空白化 (メッセージ中の FROM/JOIN を誤検出しないため)
// ・"..." / `...` / [...] は SQL の 識別子クォートなので保持する
function _stripSqlNoise(text) {
var s = String(text), out = [], i = 0, n = s.length;
while (i < n) {
var c = s.charAt(i), c2 = (i + 1 < n) ? s.charAt(i + 1) : '';
if (c === '/' && c2 === '*') { var e = s.indexOf('*/', i + 2); i = (e < 0) ? n : e + 2; out.push(' '); continue; }
if (c === '-' && c2 === '-') { var e2 = s.indexOf('\n', i + 2); i = (e2 < 0) ? n : e2; out.push(' '); continue; }
if (c === "'") {
i++;
while (i < n) {
if (s.charAt(i) === "'" && s.charAt(i + 1) === "'") { i += 2; continue; } // SQL の '' エスケープ
if (s.charAt(i) === "'") { i++; break; }
i++;
}
out.push(' ');
continue;
}
out.push(c); i++;
}
return out.join('');
}
// SQL テキストから文字列リテラル ('...') の内容を抽出 ('' エスケープは ' に復元)。
// コメント内のリテラルは対象外。 動的SQL (EXECUTE IMMEDIATE / PREPARE ... FROM /
// sp_executesql 等) がリテラル内に組み立てる SQL の抽出 (テスター指摘 No.6) に使う。
function _collectSqlLiterals(text) {
var s = String(text), out = [], i = 0, n = s.length;
while (i < n) {
var c = s.charAt(i), c2 = (i + 1 < n) ? s.charAt(i + 1) : '';
if (c === '/' && c2 === '*') { var e = s.indexOf('*/', i + 2); i = (e < 0) ? n : e + 2; continue; }
if (c === '-' && c2 === '-') { var e2 = s.indexOf('\n', i + 2); i = (e2 < 0) ? n : e2; continue; }
if (c === "'") {
i++;
var buf = [];
while (i < n) {
if (s.charAt(i) === "'" && s.charAt(i + 1) === "'") { buf.push("'"); i += 2; continue; }
if (s.charAt(i) === "'") { i++; break; }
buf.push(s.charAt(i)); i++;
}
out.push(buf.join(''));
continue;
}
i++;
}
return out;
}
// JS テキストからコメント (// , /* */) を除去。 文字列リテラルは残す
// (内部の SQL は scanJs が「SQL らしさ」で判定して抽出するため。 コメント中の
// FROM/JOIN は確実にテーブルでないので、 ここで落とすことで誤検出を防ぐ)。
function _stripJsComments(text) {
var s = String(text), out = [], i = 0, n = s.length;
while (i < n) {
var c = s.charAt(i), c2 = (i + 1 < n) ? s.charAt(i + 1) : '';
if (c === '/' && c2 === '*') { var e = s.indexOf('*/', i + 2); i = (e < 0) ? n : e + 2; out.push(' '); continue; }
if (c === '/' && c2 === '/') { var e2 = s.indexOf('\n', i + 2); i = (e2 < 0) ? n : e2; out.push(' '); continue; }
if (c === "'" || c === '"' || c === '`') {
var q = c; out.push(c); i++;
while (i < n) {
var d = s.charAt(i);
if (d === '\\') { out.push(d); if (i + 1 < n) out.push(s.charAt(i + 1)); i += 2; continue; }
out.push(d); i++;
if (d === q) break;
}
continue;
}
out.push(c); i++;
}
return out.join('');
}
// JS 内の DB 接続取得呼出の検出 regex (scanTableRefs / _analyzeJsConnSegments 共通)。
// グループ: [1]=getOtherDBConn の接続番号 / [2]=getTalonDbConfig / [3]=getDbConfig
function _jsConnRe() {
return /TALON\.(?:getOtherDBConn\s*\(\s*['"]?(\d+)['"]?\s*\)|(getTalonDbConfig)\s*\(\s*\)|(getDbConfig)\s*\(\s*\))/g;
}
// JS テキスト (コメント除去済) の文字列リテラル範囲を [start, end) で列挙。
// 接続呼出の検出や識別子探索を「文字列の外」に限定するために使う。
function _jsStringSpans(text) {
var spans = [], i = 0, n = text.length;
while (i < n) {
var c = text.charAt(i);
if (c === "'" || c === '"' || c === '`') {
var st = i; i++;
while (i < n) {
var d = text.charAt(i);
if (d === '\\') { i += 2; continue; }
i++;
if (d === c) break;
}
spans.push([st, i]);
continue;
}
i++;
}
return spans;
}
// ★Ver1.0.12 (No.167): 区間は開始位置昇順 → 二分探索 (旧: 線形走査。 Nashorn では 1 文字ごとに呼ばれて 1 機能あたり 70 秒超)
function _inSpans(spans, idx) {
var lo = 0, hi = spans.length - 1;
while (lo <= hi) {
var mid = (lo + hi) >> 1, sp = spans[mid];
if (idx < sp[0]) hi = mid - 1;
else if (idx >= sp[1]) lo = mid + 1;
else return true;
}
return false;
}
// テスター指摘 No.30 (残課題): `var sql = 'SELECT ...'; TalonDbUtil.select(TALON.getXXX(), sql);`
// のように SQL リテラルの宣言が接続取得呼出より「前」にある書き方は、 区間分割 (接続呼出は
// 後続テキストに効く) だとリテラルが 1 つ前の区間に落ちて誤帰属する。
// ここで 変数 → SQL リテラル のバインディングを収集し、 接続取得と同一引数リスト内で
// 参照される変数の SQL をその接続に帰属させて返す。 解決に使ったリテラルは rest 上で
// 空白化する (後続の区間分割スキャンで二重抽出しないため)。
// 戻り値: { resolved: [{sql, db}], rest, spans }
// db: null=既定接続先 / ''=主接続先 明示 / '1'..'15'=複数DB接続先
function _semisOutsideSpans(text, spans) {
var out = [], n = text.length, si = 0;
for (var i = 0; i < n; i++) {
if (text.charCodeAt(i) !== 59) continue; // ';'
while (si < spans.length && spans[si][1] <= i) si++;
if (si < spans.length && i >= spans[si][0] && i < spans[si][1]) continue;
out.push(i);
}
return out;
}
// ★Ver1.0.12 (No.167): 値セグメントの終端 (文字列外の ';') と区間の探索を二分探索に、 消費リテラルの空白化を 1 パスに。
// 結果 (resolved / rest / spans) は旧実装と同一 (実 JS 4 本で突合)。
function _resolveJsSqlBindings(text) {
var spans = _jsStringSpans(text);
var semis = _semisOutsideSpans(text, spans);
function nextSemi(from) { // from 以上で最初の ';' (文字列の外)。 無ければ text.length
var lo = 0, hi = semis.length - 1, ans = text.length;
while (lo <= hi) {
var mid = (lo + hi) >> 1;
if (semis[mid] >= from) { ans = semis[mid]; hi = mid - 1; } else lo = mid + 1;
}
return ans;
}
function firstSpanAt(from) { // 開始位置が from 以上の最初の区間の添字
var lo = 0, hi = spans.length - 1, ans = spans.length;
while (lo <= hi) {
var mid = (lo + hi) >> 1;
if (spans[mid][0] >= from) { ans = mid; hi = mid - 1; } else lo = mid + 1;
}
return ans;
}
// ── 1. 代入文 (var x = <リテラル連結>) の収集 ──
var bindings = {};
var asgRe = /(?:\bvar\s+|\blet\s+|\bconst\s+)?([A-Za-z_$][A-Za-z0-9_$]*)\s*(\+?=)(?![=>])/g;
var am;
while ((am = asgRe.exec(text)) !== null) {
if (_inSpans(spans, am.index)) continue;
var before = am.index > 0 ? text.charAt(am.index - 1) : '';
if (before === '.') continue;
var name = am[1], op = am[2];
var segStart = asgRe.lastIndex, segEnd = nextSemi(segStart);
var ownContent = [], ownSpans = [];
for (var sp = firstSpanAt(segStart); sp < spans.length && spans[sp][0] < segEnd; sp++) {
ownContent.push(text.substring(spans[sp][0] + 1, Math.max(spans[sp][0] + 1, spans[sp][1] - 1)));
ownSpans.push(spans[sp]);
}
if (ownContent.length === 0) continue;
var list = bindings[name] || (bindings[name] = []);
var prev = list.length > 0 ? list[list.length - 1] : null;
var isAppend = (op === '+=');
if (!isAppend && prev) {
var selfRe = new RegExp('\\b' + name.replace(/\$/g, '\\$') + '\\b', 'g');
var seg = text.substring(segStart, segEnd), sm2;
while ((sm2 = selfRe.exec(seg)) !== null) {
if (!_inSpans(spans, segStart + sm2.index)) { isAppend = true; break; }
}
}
var content = ownContent.join(' ');
var allSpans = ownSpans;
if (isAppend && prev) {
content = prev.content + ' ' + content;
allSpans = prev.spans.concat(ownSpans);
}
list.push({ start: am.index, content: content, spans: allSpans });
}
// ── 2. 接続取得呼出サイトの後続引数から 変数参照を解決 ──
var resolved = [];
var consumed = {};
var connRe = _jsConnRe();
var cm;
while ((cm = connRe.exec(text)) !== null) {
if (_inSpans(spans, cm.index)) continue;
var db = (cm[1] != null) ? cm[1] : ((cm[2] != null) ? '' : null);
var p = connRe.lastIndex;
while (p < text.length && /\s/.test(text.charAt(p))) p++;
if (text.charAt(p) !== ',') continue;
var argEnd = text.length, depth = 0;
for (var q = p + 1; q < text.length; q++) {
if (_inSpans(spans, q)) continue;
var qc = text.charAt(q);
if (qc === '(') depth++;
else if (qc === ')') { if (depth === 0) { argEnd = q; break; } depth--; }
}
var idRe = /[A-Za-z_$][A-Za-z0-9_$]*/g;
idRe.lastIndex = 0;
var argText = text.substring(p + 1, argEnd);
var im;
while ((im = idRe.exec(argText)) !== null) {
var absIdx = p + 1 + im.index;
if (_inSpans(spans, absIdx)) continue;
var cand = bindings[im[0]];
if (!cand) continue;
var hit = null;
for (var ci2 = 0; ci2 < cand.length; ci2++) {
if (cand[ci2].start < cm.index) hit = cand[ci2];
}
if (!hit) continue;
resolved.push({ sql: hit.content, db: db });
for (var hs = 0; hs < hit.spans.length; hs++) {
consumed[hit.spans[hs][0] + ':' + hit.spans[hs][1]] = true;
}
}
}
// ── 3. 消費済みリテラルを空白化 (オフセット維持、 1 パス) ──
var keys = [];
for (var key in consumed) if (consumed.hasOwnProperty(key)) keys.push(key);
var rest = text;
if (keys.length) {
var ranges = [];
for (var k = 0; k < keys.length; k++) { var pr = keys[k].split(':'); ranges.push([Number(pr[0]), Number(pr[1])]); }
ranges.sort(function (a, b) { return a[0] - b[0]; });
var parts = [], cur = 0;
for (var r = 0; r < ranges.length; r++) {
var cs = ranges[r][0], ce = ranges[r][1];
if (cs < cur) continue; // 重複区間 (同じリテラルが複数の解決に使われた) は 1 度だけ
parts.push(text.substring(cur, cs));
parts.push(new Array(ce - cs + 1).join(' '));
cur = ce;
}
parts.push(text.substring(cur));
rest = parts.join('');
}
return { resolved: resolved, rest: rest, spans: spans };
}
// JS コード (CHR_TEXT) を 接続帰属付きでスキャンするための分解 (§5.20.10 / No.30 / No.43)。
// 1. コメント除去 (★No.43: 生テキストのまま接続呼出で区間分割すると、 コメントアウトされた
// 接続呼出で区間が切れ、 2 区間目以降が「/* を含まない」ためコメント除去をすり抜けて
// ブロックコメント内の DB アクセスが誤抽出される)
// 2. 変数バインディング解決 (No.30 残: リテラル宣言が接続呼出より前の書き方)
// 3. 残テキストを接続呼出位置で区間分割 (文字列リテラル内の呼出風テキストは無視)
// 戻り値: { resolved: [{sql, db}], segments: [{text, db}] }
function _analyzeJsConnSegments(ct) {
var text = _stripJsComments(String(ct || ''));
var bind = _resolveJsSqlBindings(text);
var segments = [];
var re = _jsConnRe();
var lastEnd = 0, currentDb = null, m;
while ((m = re.exec(bind.rest)) !== null) {
if (_inSpans(bind.spans, m.index)) continue;
segments.push({ text: bind.rest.substring(lastEnd, m.index), db: currentDb });
currentDb = (m[1] != null) ? m[1] : ((m[2] != null) ? '' : null);
lastEnd = re.lastIndex;
}
segments.push({ text: bind.rest.substring(lastEnd), db: currentDb });
return { resolved: bind.resolved, segments: segments };
}
// SQL 文字列から CTE / 派生表エイリアス名 (UPPER) を収集 (テーブル誤検出の除外用)。
// 例: WITH SUB AS (...) / , TMP AS (...) — これらは物理テーブルではないので除外する。
function _collectSqlLocalNames(sql) {
var set = {};
var reAs = new RegExp('([A-Za-z_$\\u0080-\\uffff][A-Za-z0-9_$\\u0080-\\uffff]*)\\s+AS\\s*\\(', 'gi');
var m;
while ((m = reAs.exec(sql)) !== null) set[String(m[1]).toUpperCase()] = true;
return set;
}
// SQL 予約語など、 テーブル名として採用しない語。
function _sqlSkipWord(u) {
var skip = { 'DUAL': 1, 'SELECT': 1, 'WHERE': 1, 'AND': 1, 'OR': 1, 'NULL': 1,
'TRUE': 1, 'FALSE': 1, 'TABLE': 1, 'SET': 1, 'VALUES': 1, 'AS': 1, 'BY': 1,
'ON': 1, 'IN': 1, 'EXISTS': 1, 'CASE': 1, 'WHEN': 1, 'THEN': 1, 'END': 1, 'ELSE': 1,
// ★Ver1.0.22 (No.194): 句のキーワードが続く形 (FROM ... TO / JOIN の直後に別の句) で拾われた語
'TO': 1, 'FROM': 1, 'INTO': 1, 'JOIN': 1, 'LEFT': 1, 'RIGHT': 1, 'INNER': 1, 'OUTER': 1, 'FULL': 1, 'CROSS': 1, 'NATURAL': 1,
'UPDATE': 1, 'INSERT': 1, 'DELETE': 1, 'MERGE': 1, 'USING': 1, 'WITH': 1, 'ORDER': 1, 'GROUP': 1, 'HAVING': 1, 'UNION': 1,
'DISTINCT': 1, 'ALL': 1, 'IS': 1, 'NOT': 1, 'LIKE': 1, 'BETWEEN': 1, 'ONLY': 1, 'LATERAL': 1 };
return !!skip[u];
}
// テーブル名として成立する形か (★Ver1.0.22、 テスター指摘 No.194): 文字・数字・_ $ #・多バイト文字 (日本語) を含み、
// バックスラッシュ / スラッシュ / カンマ / セミコロン / 読点・句点 / 空白 を含まない。 設計書出力の本体 JS は画面用の JS を
// 文字列で持つため、 その中の .join("\\n") の JOIN が SQL の JOIN と読まれて "\\n" / ", " / " " / "、" がテーブル名になっていた
function _sqlNameLike(u) {
var s = String(u == null ? '' : u);
if (!/[A-Za-z0-9_\u00C0-\u2FFF\u3040-\u30FF\u3400-\u9FFF\uF900-\uFAFF\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/.test(s)) return false;
if (/[\\\/,;\u3001\u3002\s]/.test(s)) return false;
return true;
}
// 修飾付き識別子パターン (schema.table) — 詳細は _qrefPat。
function _qrefPat() {
var seg = '(?:"[^"]+"|`[^`]+`|\\[[^\\]]+\\]|[A-Za-z_$\\u0080-\\uffff][A-Za-z0-9_$\\u0080-\\uffff]*)';
return '(' + seg + '(?:\\s*\\.\\s*' + seg + ')*)';
}
function _dequoteIdent(s) {
s = String(s).replace(/^\s+|\s+$/g, '');
var n = s.length;
if (n >= 2) {
var a = s.charAt(0), b = s.charAt(n - 1);
if ((a === '"' && b === '"') || (a === '`' && b === '`')) return s.substring(1, n - 1);
if (a === '[' && b === ']') return s.substring(1, n - 1);
}
return s;
}
// 修飾付き参照 (schema.table) から実テーブル名 (最終セグメント) を取り出す。
// スキーマ名をテーブル名と誤認しないために必須。
function _tableNameFromRef(ref) {
if (!ref) return '';
var parts = String(ref).split('.');
return _dequoteIdent(parts[parts.length - 1]);
}
// トップレベル (括弧外) カンマで分割 (FROM の カンマ結合解析用)
function _splitTopLevelComma(str) {
var out = [], depth = 0, cur = '', n = str.length;
for (var i = 0; i < n; i++) {
var c = str.charAt(i);
if (c === '(') { depth++; cur += c; }
else if (c === ')') { if (depth > 0) depth--; cur += c; }
else if (c === ',' && depth === 0) { out.push(cur); cur = ''; }
else cur += c;
}
if (cur.length) out.push(cur);
return out;
}
// SQL 文字列からテーブル参照を抽出 (UPPER 名の {read, write})。 全スキャン共通コア。
// ・schema.table / db.schema.table は最終セグメント (実テーブル名) を採用 (スキーマ誤認防止)
// ・FROM のカンマ結合 (FROM a, b, c) を各テーブルとして検出 (旧式結合)
// ・FROM/JOIN 直後の括弧、 CTE / 派生表エイリアス除外、 multibyte・各種クォート対応
function _collectSqlTableNames(sqlText) {
if (!sqlText) return { read: [], write: [] };
var read = {}, write = {};
var s = _stripSqlNoise(sqlText);
var local = _collectSqlLocalNames(s);
var QREF = _qrefPat();
function addName(map, name) {
if (!name) return;
var u = String(name).toUpperCase();
if (_sqlSkipWord(u) || local[u] || !_sqlNameLike(u)) return; // ★Ver1.0.22 (No.194): 識別子の形をしていない語は捨てる
map[u] = true;
}
function addRef(map, refStr) { addName(map, _tableNameFromRef(refStr)); }
var m, re;
// FROM 句 (カンマ結合含む): FROM の後を 句境界まで取り出し トップレベルカンマで分割。
var boundary = /^\s*\b(WHERE|GROUP\b|HAVING|ORDER\b|UNION|INTERSECT|MINUS|EXCEPT|CONNECT\b|START\b|FETCH\b|FOR\b|JOIN|INNER\b|LEFT\b|RIGHT\b|FULL\b|CROSS\b|NATURAL\b|OUTER\b)/i;
var qHead = new RegExp('^' + QREF);
var fromKw = /(^|[^.\w])FROM\b/gi, fm; // ★Ver1.0.22 (No.194): ".from(" (JS のメソッド) は FROM ではない
while ((fm = fromKw.exec(s)) !== null) {
var p = fm.index + fm[0].length, depth = 0, buf = '', j = p;
while (j < s.length) {
var ch = s.charAt(j);
if (ch === '(') { depth++; buf += ch; j++; continue; }
if (ch === ')') { if (depth === 0) break; depth--; buf += ch; j++; continue; }
// 句境界キーワード (WHERE/JOIN/ORDER 等) は「単語の先頭」でのみ成立させる。
// s.substr(j,12) は部分文字列の先頭が常に ^\b 扱いになるため、 直前文字が
// 単語文字 (例: TLN_..._ORDER の '_') の場合は途中一致なので境界とみなさない。
// (これを怠ると、 末尾が ORDER/GROUP 等のテーブル名で FROM 句が途中打ち切りになる)
var atWordStart = (j === 0) || !/\w/.test(s.charAt(j - 1));
if (depth === 0 && (ch === ';' || (/[A-Za-z]/.test(ch) && atWordStart && boundary.test(s.substr(j, 12))))) break;
buf += ch; j++;
}
var segs = _splitTopLevelComma(buf);
for (var si = 0; si < segs.length; si++) {
var seg = segs[si].replace(/^\s+/, '');
if (seg.charAt(0) === '(') continue; // サブクエリ (内側 FROM は別途検出)
var tm = seg.match(qHead);
if (tm) addRef(read, tm[1]);
}
}
re = new RegExp('(^|[^.\\w])JOIN[\\s(]+' + QREF, 'gi'); while ((m = re.exec(s)) !== null) addRef(read, m[2]); // ★Ver1.0.22 (No.194): ".join(" は JOIN ではない
re = new RegExp('\\bINSERT\\s+INTO\\s+' + QREF, 'gi'); while ((m = re.exec(s)) !== null) addRef(write, m[1]);
re = new RegExp('\\bUPDATE\\s+' + QREF + '\\s+SET\\b', 'gi'); while ((m = re.exec(s)) !== null) addRef(write, m[1]);
re = new RegExp('\\bDELETE\\s+FROM[\\s(]+' + QREF, 'gi'); while ((m = re.exec(s)) !== null) addRef(write, m[1]);
re = new RegExp('\\bMERGE\\s+INTO\\s+' + QREF, 'gi'); while ((m = re.exec(s)) !== null) addRef(write, m[1]);
// REPLACE INTO (MySQL の UPSERT 系 DML = 書き込み) — テスター指摘 No.4。
// ★INTO を必須にする: MySQL 文法上 INTO は省略可だが、 REPLACE は SQL 関数名でもあり
// 「REPLACE <識別子>」 まで許すと REPLACE(col, ...) や英文中の replace を誤検出する。
re = new RegExp('\\bREPLACE\\s+INTO\\s+' + QREF, 'gi'); while ((m = re.exec(s)) !== null) addRef(write, m[1]);
// MERGE の USING 句のソース表 (= 読み取り) — テスター指摘 No.5。
// JOIN ... USING (col) / EXECUTE ... USING 変数 と誤認しないよう、
// MERGE INTO <表> [別名] USING <表> の並びに限定して抽出する。
// USING (SELECT ...) のサブクエリは内側の FROM を既存スキャンが拾うため対象外。
re = new RegExp('\\bMERGE\\s+INTO\\s+' + QREF +
'(?:\\s+(?:AS\\s+)?[A-Za-z_$\\u0080-\\uffff][A-Za-z0-9_$\\u0080-\\uffff]*)?\\s+USING\\s+' + QREF, 'gi');
while ((m = re.exec(s)) !== null) addRef(read, m[2]);
// 動的SQL (EXECUTE IMMEDIATE / PREPARE ... FROM / sp_executesql 等) — テスター指摘 No.6。
// _stripSqlNoise は文字列リテラルを除去するため、 リテラル内に組み立てた SQL は上の
// スキャンでは拾えない。 原文からリテラルを抽出し、 内容が DML 文で「始まる」ものだけを
// SQL とみなして再帰走査する (メッセージ等の「DML 語を含むだけ」の文字列は先頭一致
// しないため対象外)。 'UPDATE ' || 変数 のような動的テーブル名は解決不能 (注記に明記)。
var dmlHead = /^\s*(SELECT|INSERT|UPDATE|DELETE|MERGE|REPLACE|WITH)\b/i;
var lits = _collectSqlLiterals(sqlText);
for (var li = 0; li < lits.length; li++) {
if (!dmlHead.test(lits[li])) continue;
var sub = _collectSqlTableNames(lits[li]);
for (var sr = 0; sr < sub.read.length; sr++) addName(read, sub.read[sr]);
for (var sw = 0; sw < sub.write.length; sw++) addName(write, sub.write[sw]);
}
return { read: Object.keys(read), write: Object.keys(write) };
}
// SQL 文字列からテーブル参照を抽出して readArr / writeArr (UPPER) に push する。
// コード概要チップ等、 出典タグ不要な箇所で _collectSqlTableNames を再利用する。
function _pushSqlTables(sqlText, readArr, writeArr) {
var r = _collectSqlTableNames(sqlText);
for (var i = 0; i < r.read.length; i++) readArr.push(r.read[i]);
for (var w = 0; w < r.write.length; w++) writeArr.push(r.write[w]);
}
// JS コードから SQL を含む文字列リテラルだけを抽出し _pushSqlTables にかける。
// コメント除去 + DML キーワードを含むリテラルのみ対象 (メッセージ/コメント誤検出を防ぐ)。
// JS コード内の文字列リテラルを抽出し、 '+' 演算子で連結されたリテラル列を 1 つに結合して返す。
// TALON の JS は SQL を 'SELECT ...' + ' FROM TBL ' + ' WHERE ...' のように 複数リテラルへ
// 分割して書く。 リテラル単位で DML 判定すると、 テーブル名を含む 'FROM TBL' のリテラルが
// DML キーワードを持たず取りこぼされる (= 参照テーブル検出漏れ)。 連結を復元してから判定する。
// 結合の条件: リテラル間のテキストが「空白 と + のみ」であること (変数や ) ; , が挟まれば分割)。
// 戻り値: [連結後の文字列, ...] (DML 判定は呼び出し側)
function _joinJsSqlLiterals(jsText) {
var out = [];
if (!jsText) return out;
var s = _stripJsComments(jsText);
var litRe = /'((?:\\.|[^'\\])*)'|"((?:\\.|[^"\\])*)"|`((?:\\.|[^`\\])*)`/g;
var gapJoin = /^[\s+]*\+[\s+]*$/; // リテラル間が「+ と空白のみ」= 連結とみなす
var cur = null, prevEnd = -1, lm;
while ((lm = litRe.exec(s)) !== null) {
var content = (lm[1] !== undefined) ? lm[1] : ((lm[2] !== undefined) ? lm[2] : lm[3]);
if (content === undefined || content === null) content = '';
var gap = (prevEnd >= 0) ? s.substring(prevEnd, lm.index) : null;
if (cur !== null && gap !== null && gapJoin.test(gap)) {
cur += content;
} else {
if (cur !== null) out.push(cur);
cur = content;
}
prevEnd = litRe.lastIndex;
}
if (cur !== null) out.push(cur);
return out;
}
function _pushSqlTablesFromJs(jsText, readArr, writeArr) {
if (!jsText) return;
var dmlRe = _dmlKeywordRe();
var groups = _joinJsSqlLiterals(jsText);
for (var gi = 0; gi < groups.length; gi++) {
if (!dmlRe.test(groups[gi])) continue;
_pushSqlTables(groups[gi], readArr, writeArr);
}
}
// ── 共有ヘルパ (重複定義の一元化) ──────────────────────────
// トップレベル var のミュータブル状態は Nashorn の関数スコープで undefined 化する
// ハマりがあるため (=_procSrcCache の教訓)、 定数はすべて関数が返すリテラルにする。
// 「SQL らしさ」判定の DML キーワード (scanJs / _pushSqlTablesFromJs 共通)
function _dmlKeywordRe() {
return /\b(SELECT|INSERT|UPDATE|DELETE|MERGE|REPLACE|WITH)\b/i;
}
// FUNC_SEQ (正規化) → 表示ブロック番号 (SORT+1 — §5.3 の表記規則) のマップを構築。
// _collectProcRefs / renderCodebook / mdSecCodebook 共通。
function _buildSeqBlockMap(ctx) {
var map = {};
if (!ctx || !ctx.sql) return map;
for (var i = 0; i < _scanSizeOf(ctx.sql); i++) {
var r = ctx.sql[i];
var seq = TFC.s(r['FUNC_SEQ']);
if (seq === '' || seq === '-1') continue;
map[String(Number(seq))] = Number(TFC.s(r['SORT'])) + 1;
}
return map;
}
// TLN_M_GENERAL_APP のプロシージャ名系 FUNC_KBN → 設定箇所ラベルキー (TFC.t)。
// キー集合としても使う (_getCalledBlockRefs / _collectProcRefs 共通)。
function _plSqlNameLabelKeys() {
return { PL_SQL_NAME: 'cb.procPlaceConfirmBefore', PL_SQL_NAME_AFTER: 'cb.procPlaceConfirmAfter',
PL_SQL_NAME_DL: 'cb.procPlaceDlBefore', PL_SQL_NAME_AFTER_DL: 'cb.procPlaceDlAfter',
PL_SQL_NAME_SEARCH: 'cb.procPlaceSearchBefore', PL_SQL_NAME_SEARCH_AFTER: 'cb.procPlaceSearchAfter' };
}
// コードブック (HTML / MD) の対象 FUNC_KBN 判定 (JS/CSS コード本体を持つもののみ)。
// 除外: SEND_MAIL.CHR_TEXT (本文) / OTHER_FUNC.CHR_TEXT (処理名) / TITLE_NOTE /
// CHART_SERIES_BASE (系列ラベル) / INIT_VALUE_TEXT 等の非コード CHR_TEXT。
function _isCodebookCodeKbn(fk) {
if (fk === 'JAVA_SCRIPT' || fk === 'JAVA_SCRIPT_ENGINE' ||
fk === 'JAVASCRIPT' || fk === 'JAVASCRIPT_ENGINE' ||
fk === 'FOCUS_OUT_JAVASCRIPT' || fk === 'CSS') return true;
if (fk === 'BUTTON_BAT' || /^BUTTON_BAT_(\d+|CLIENT_JAVASCRIPT)$/.test(fk)) return true;
if (fk === 'BUTTON_AJAX' || /^BUTTON_AJAX_(\d+|CLIENT_JAVASCRIPT)$/.test(fk)) return true;
if (fk === 'BUTTON_NEXT' || /^BUTTON_NEXT_(\d+|CLIENT_JAVASCRIPT)$/.test(fk)) return true;
if (fk === 'BUTTON_REPORT' || fk === 'BUTTON_REPORT_JAVASCRIPT' ||
fk === 'BUTTON_REPORT_JAVASCRIPT_ON_CLICK') return true;
return false;
}
// ストアドプロシージャ本体ソースの取得 (DB 方言別カタログから)。 名前→ソース文字列をキャッシュ。
// パッケージ/スキーマ修飾 (A.B) に備え ドット分割の各セグメントも候補に含める。
// 対応: Oracle (ALL_SOURCE) / PostgreSQL (pg_get_functiondef) /
// MySQL (INFORMATION_SCHEMA.ROUTINES) / SQL Server (sys.sql_modules)。
// db2 / unknown は当面空を返す。
var _procSrcCache = {};
var _procDbTypeCache = null;
// DB 方言の判定。 TFC.detectDbType は検出用に begin()/rollback() を張るため、
// 生成処理中に呼ぶとアクティブなトランザクションを終了させてしまい
// 後続の selectPS が TransactionNotYetBegunException になる。
// ここでは selectPS と同じ _getConn (安全に auto-begin、 rollback しない) で
// 取得した接続の productName から判定する (probe トランザクションを張らない)。
function _procDbType() {
if (_procDbTypeCache) return _procDbTypeCache;
if (_scanDbTypeOverride) { _procDbTypeCache = _scanDbTypeOverride; return _procDbTypeCache; }
var t = 'oracle';
try {
var conn = _getConn(TALON.getDbConfig());
var pn = String(conn.getMetaData().getDatabaseProductName() || '').toLowerCase();
if (pn.indexOf('oracle') >= 0) t = 'oracle';
else if (pn.indexOf('postgresql') >= 0) t = 'postgres';
else if (pn.indexOf('mysql') >= 0 || pn.indexOf('mariadb') >= 0) t = 'mysql';
else if (pn.indexOf('sql server') >= 0) t = 'sqlserver';
else if (pn.indexOf('db2') >= 0) t = 'db2';
else t = 'unknown';
} catch (eD) {
try { TALON.getLogger().writeInfo('[TFC] proc dbType 検出失敗 → oracle: ' + eD); } catch (ig) {}
t = 'oracle';
}
_procDbTypeCache = t;
return t;
}
function _getProcSource(name) {
if (!_procSrcCache) _procSrcCache = {};
var key = TFC.s(name).replace(/^\s+|\s+$/g, '').toUpperCase();
if (!key) return '';
if (key in _procSrcCache) return _procSrcCache[key];
var cands = [key], seen = {};
seen[key] = 1;
if (key.indexOf('.') >= 0) {
var parts = key.split('.');
var last = parts[parts.length - 1], first = parts[0];
if (!seen[last]) { seen[last] = 1; cands.push(last); }
if (!seen[first]) { seen[first] = 1; cands.push(first); }
}
var dbType = _procDbType();
var src = '';
try {
var ph = cands.map(function () { return '?'; }).join(',');
var sql, params;
if (dbType === 'postgres') {
// pg_proc.proname は小文字保存。 候補も小文字化して照合。
// pg_get_functiondef は CREATE FUNCTION/PROCEDURE 全文 (本体含む) を返す。
var candsLower = cands.map(function (c) { return c.toLowerCase(); });
sql = "SELECT pg_get_functiondef(p.oid) AS TEXT FROM pg_proc p " +
"JOIN pg_namespace n ON n.oid = p.pronamespace " +
"WHERE n.nspname NOT IN ('pg_catalog','information_schema') " +
"AND lower(p.proname) IN (" + ph + ")";
params = candsLower;
} else if (dbType === 'mysql') {
sql = "SELECT ROUTINE_DEFINITION AS TEXT FROM INFORMATION_SCHEMA.ROUTINES " +
"WHERE ROUTINE_SCHEMA = DATABASE() AND UPPER(ROUTINE_NAME) IN (" + ph + ")";
params = cands;
} else if (dbType === 'sqlserver') {
sql = "SELECT m.definition AS TEXT FROM sys.sql_modules m " +
"JOIN sys.objects o ON o.object_id = m.object_id " +
"WHERE UPPER(o.name) IN (" + ph + ")";
params = cands;
} else if (dbType === 'oracle') {
sql = "SELECT TEXT FROM ALL_SOURCE WHERE OWNER = SYS_CONTEXT('USERENV','CURRENT_SCHEMA') " +
"AND NAME IN (" + ph + ") AND TYPE IN ('PROCEDURE','FUNCTION','PACKAGE BODY') " +
"ORDER BY NAME, TYPE, LINE";
params = cands;
} else {
// db2 / unknown / cdata: プロシージャ本体取得は未対応
_procSrcCache[key] = '';
return '';
}
var rows = _scanSelect(sql, params);
var buf = [];
for (var i = 0; i < rows.length; i++) buf.push(TFC.s(rows[i]['TEXT']));
// Oracle は ALL_SOURCE 行を行単位で連結 (改行込み)、 他DBは 1 行=全文を改行区切り。
src = buf.join(dbType === 'oracle' ? '' : '\n');
} catch (e) {
try { TALON.getLogger().writeInfo('[TFC] プロシージャソース取得スキップ (' + name + ', db=' + dbType + '): ' + e); } catch (ig) {}
src = '';
}
_procSrcCache[key] = src;
return src;
}
// 機能が参照するストアドプロシージャ名を収集 (テーブル入出力抽出 / コードブックで共用)。
// 格納箇所:
// ・TLN_M_GENERAL_ITEM_OPTN FUNC_KBN='BUTTON_BAT' AND FLAG='0' → CHR1
// ([ブロック]処理呼出 > プロシージャ呼出。 1 ブロックに複数ボタン可 = 複数行を全件収集)
// ・TLN_M_GENERAL_APP FUNC_KBN=PL_SQL_NAME系 → VALUE (確定/明細/検索 の前後)
// 返り値: { procName: { seq: 代表FUNC_SEQ, places: [設定箇所ラベル, ...] } }
// (テスター指摘 No.3: 同名 proc が複数箇所に設定され得るため、 どの設定箇所で
// 呼ばれるかを保持してコードブックに表示する。 ブロック番号は SORT+1 表示規則)
function _collectProcRefs(ctx) {
var procRefs = {};
var seqBlock = _buildSeqBlockMap(ctx); // FUNC_SEQ (正規化) → 表示ブロック番号 (SORT+1)
function placeOf(labelKey, funcSeq) {
var lbl = TFC.t(labelKey, _scanLang);
var seqS = TFC.s(funcSeq);
if (seqS === '-1') return lbl + ' (' + TFC.t('cb.funcLevel', _scanLang) + ')';
var bn = seqBlock[String(Number(seqS))];
return lbl + (bn ? ' (BLOCK ' + bn + ')' : '');
}
function addProc(pn, seq, place) {
if (!pn) return;
if (!(pn in procRefs)) procRefs[pn] = { seq: seq, places: [] };
if (procRefs[pn].places.indexOf(place) < 0) procRefs[pn].places.push(place);
}
if (ctx && ctx.optn) {
for (var pi = 0; pi < _scanSizeOf(ctx.optn); pi++) {
var po = ctx.optn[pi];
if (TFC.s(po['FUNC_KBN']) === 'BUTTON_BAT' && TFC.s(po['FLAG']) === '0') {
var pn = TFC.s(po['CHR1']);
if (pn) addProc(pn, TFC.s(po['FUNC_SEQ']), placeOf('cb.procPlaceBatButton', TFC.s(po['FUNC_SEQ'])));
}
}
}
if (ctx && ctx.app) {
var plKbn = _plSqlNameLabelKeys();
for (var pj = 0; pj < _scanSizeOf(ctx.app); pj++) {
var pa = ctx.app[pj];
var paKbn = TFC.s(pa['FUNC_KBN']);
if (plKbn[paKbn]) {
var pnm = TFC.s(pa['VALUE']);
if (pnm) addProc(pnm, TFC.s(pa['FUNC_SEQ']), placeOf(plKbn[paKbn], TFC.s(pa['FUNC_SEQ'])));
}
}
}
return procRefs;
}
// 他機能呼出 (OTHER_FUNC) の呼出先ブロックが更新するテーブルを DB 横断で取得。
// 呼出先は CHR2=機能ID / NUM1=ブロック FUNC_SEQ で特定 (出典: TALON OtherFuncStruct
// .setFieldValue → CHR2=funcId, NUM1=blockIndex)。 呼出先ブロックの UPDATE_TABLE が
// 呼出元の登録/更新/削除に連動して INSERT/UPDATE/DELETE/MERGE される (manual 5.13.1)。
// 呼出先機能は選択機能集合に含まれないことが多いため、 selectPS で都度引く (キャッシュ)。
// ★No.42: 取り込むのは「連動更新で実際に実行されるもの」だけに限定する
// (出典: TALON 本体 BaseProcess.executeOtherFunc — 呼出先ブロックについて実行されるのは
// 対象行 SELECT / 処理前後 JS (UPDATE_BEFORE・UPDATE_AFTER) / 処理前後プロシージャ
// (PL_SQL_NAME・PL_SQL_NAME_AFTER) / UPDATE_TABLE への DML / 設定値登録 / メール送信):
// ・UPDATE_TABLE (書き) + BODY_SQL/TITLE_SQL (対象行 SELECT の読み)
// ・ブロック処理前後 JS = ITEM_OPTN の JAVA_SCRIPT_ENGINE × UPDATE_BEFORE/UPDATE_AFTER のみ
// ・ブロック処理前後プロシージャ = APP の PL_SQL_NAME / PL_SQL_NAME_AFTER のみ
// 取り込まないもの (ボタン・画面操作起点のため連動更新では実行されない — テスター指摘 No.42):
// 帳票出力の処理後 JS (BUTTON_REPORT) / 項目の JS 呼出ボタン (JAVASCRIPT・JAVASCRIPT_ENGINE) /
// 処理呼出 (BUTTON_BAT) の JavaScript・プロシージャ / 非同期通信 (BUTTON_AJAX) /
// フォーカスアウト JS / 検索前後 JS・プロシージャ / 帳票前後プロシージャ (DL 系)
// ★1 階層のみ: 呼出先ブロックがさらに持つ OTHER_FUNC は辿らない (manual: 他機能呼出は
// 指定ブロックのみ実行)。
// 返り値: { tables: [UPDATE_TABLE...], read: [...], write: [...], title, funcNm }
var _calledBlockCache = {};
var _clobTypeForCalled = null;
function _readClobVal(v) {
if (v == null) return '';
try {
if (!_clobTypeForCalled) _clobTypeForCalled = Java.type('java.sql.Clob');
if (v instanceof _clobTypeForCalled) {
var len = v.length();
return len > 0 ? String(v.getSubString(1, len)) : '';
}
} catch (e) { return ''; }
return String(v);
}
function _getCalledBlockRefs(funcId, funcSeq) {
if (!_calledBlockCache) _calledBlockCache = {};
var key = TFC.s(funcId).toUpperCase() + '#' + TFC.s(funcSeq);
if (key in _calledBlockCache) return _calledBlockCache[key];
var info = { tables: [], read: [], write: [], title: '', funcNm: '' };
var seqWant = String(Number(TFC.s(funcSeq)));
try {
var procNames = {}; // 呼出先ブロックが呼ぶプロシージャ名の集合
var fn = _scanSelect("SELECT FUNC_NM FROM TLN_M_GENERAL_FUNC WHERE FUNC_ID = ?", [TFC.s(funcId)]);
if (fn.length > 0) info.funcNm = TFC.s(fn[0]['FUNC_NM']);
// UPDATE_TABLE (宣言的な更新先 = 書き込み) と 処理前後プロシージャを APP から取得。
// ★No.42: 連動更新で実行されるのは PL_SQL_NAME (処理前) / PL_SQL_NAME_AFTER (処理後)
// のみ。 帳票 (DL 系) / 検索 (SEARCH 系) のプロシージャは実行されないため除外。
// FUNC_SEQ は数値列。 文字列をバインドすると PostgreSQL で型不一致 (integer = text)
// になるため、 FUNC_ID だけで引いて FUNC_SEQ は JS 側で照合する (DB 横断で安全)。
var ap = _scanSelect(
"SELECT FUNC_KBN, FUNC_SEQ, VALUE FROM TLN_M_GENERAL_APP WHERE FUNC_ID = ?",
[TFC.s(funcId)]);
for (var i = 0; i < ap.length; i++) {
if (String(Number(TFC.s(ap[i]['FUNC_SEQ']))) !== seqWant) continue;
var akbn = TFC.s(ap[i]['FUNC_KBN']);
var aval = TFC.s(ap[i]['VALUE']);
if (akbn === 'UPDATE_TABLE') { if (aval) { info.tables.push(aval); info.write.push(aval); } }
else if ((akbn === 'PL_SQL_NAME' || akbn === 'PL_SQL_NAME_AFTER') && aval) procNames[aval] = 1;
}
// BODY_SQL / TITLE_SQL (読み/書き)。 CLOB は getSubString で読出。
var sq = _scanSelect(
"SELECT FUNC_SEQ, TITLE, BODY_SQL, TITLE_SQL FROM TLN_M_GENERAL_FUNC_SQL WHERE FUNC_ID = ?",
[TFC.s(funcId)]);
for (var j = 0; j < sq.length; j++) {
if (String(Number(TFC.s(sq[j]['FUNC_SEQ']))) !== seqWant) continue;
info.title = TFC.s(sq[j]['TITLE']);
_pushSqlTables(_readClobVal(sq[j]['BODY_SQL']), info.read, info.write);
_pushSqlTables(_readClobVal(sq[j]['TITLE_SQL']), info.read, info.write);
}
// CHR_TEXT (JavaScript) — ★No.42: 連動更新で実行されるのは呼出先ブロックの
// 処理前後 JS (JAVA_SCRIPT_ENGINE × UPDATE_BEFORE/UPDATE_AFTER) のみ。
// 帳票出力の処理後 JS / 項目の JS 呼出ボタン / 処理呼出 (BUTTON_BAT) の JS・
// プロシージャ / 非同期通信 / フォーカスアウト / 検索前後 JS 等のボタン・
// 画面操作起点のコードは実行されないため取り込まない。
// (COL_NAME は TALON 標準の UI コンポーネント識別子のため PG でも大文字維持だが、
// 防御的に大文字化して比較する)
var op = _scanSelect(
"SELECT FUNC_SEQ, FUNC_KBN, COL_NAME, CHR_TEXT FROM TLN_M_GENERAL_ITEM_OPTN WHERE FUNC_ID = ?",
[TFC.s(funcId)]);
for (var k = 0; k < op.length; k++) {
if (String(Number(TFC.s(op[k]['FUNC_SEQ']))) !== seqWant) continue;
var okbn = TFC.s(op[k]['FUNC_KBN']);
if (okbn !== 'JAVA_SCRIPT_ENGINE') continue;
var ocol = TFC.s(op[k]['COL_NAME']).toUpperCase();
if (ocol !== 'UPDATE_BEFORE' && ocol !== 'UPDATE_AFTER') continue;
_pushSqlTablesFromJs(_readClobVal(op[k]['CHR_TEXT']), info.read, info.write);
}
// 呼出先ブロックが呼ぶストアドプロシージャの本体も走査 (1 階層)。
var pnames = Object.keys(procNames);
for (var p = 0; p < pnames.length; p++) {
var psrc = _getProcSource(pnames[p]);
if (psrc) _pushSqlTables(psrc, info.read, info.write);
}
} catch (e) {
try { TALON.getLogger().writeInfo('[TFC] 他機能呼出 呼出先ブロック取得スキップ (' + funcId + '#' + funcSeq + '): ' + e); } catch (ig) {}
}
_calledBlockCache[key] = info;
return info;
}
// 備考欄 (TLN_M_GENERAL_FUNC.NOTE = 機能説明タブの備考) から手動依存タグを抽出する。
// スクリプト解析で捕捉できない依存 (プロシージャから呼ぶ別プロシージャ、 JS から呼ぶ
// Java 等) を利用者が明示宣言する仕組み。 タグは 1 タグ 1 テーブルで、 他の文章の中に
// 埋まっていても抽出する:
// [R:TBL] 読み込みのみ
// [W:TBL@2] 書き込みのみ (ACCESS_DB=2 を明示。 @0 = 主 TALON DB の明示)
// [WR:S1.TBL] 読み書き (RW も同義。 スキーマ修飾可)
// @N 省略時の接続先は呼び出し側で 機能レベル ACCESS_DB (アプリケーションタブの
// DB 接続先、 無ければ主 DB) に解決される (= FUNC_SEQ=-1 の参照として扱う)。
// 全角入力 ([WR:TBL@2] 等) は半角へ正規化してからパースする (IME 対策)。
// テーブル名には日本語 (かな / 漢字 / 長音 等) も使える (日本語識別子の DB 対応)。
// 返り値: [{ mode: 'R'|'W'|'WR', table: 'UPPER名', tableRaw: 'UPPER原文名',
// db: '2'|''|null, raw: '[W:TBL@2]' }]
// db: null = 省略 (既定接続先) / '' = @0 (主 DB 明示) / '1'..'15' = ACCESS_DB
// tableRaw: 全角英数字を半角化する前のテーブル名 (★No.130 の原文フォールバック候補)
function _collectNoteDepTags(noteText) {
var out = [];
if (!noteText) return out;
// タグ構文文字 ([]:@) の全角 → 半角は 常に行う (IME 対策)。
var s0 = String(noteText)
.replace(/[/g, '[').replace(/]/g, ']')
.replace(/:/g, ':').replace(/@/g, '@');
// ★全角英数字 → 半角の正規化は 既存互換のため維持する ([WR:TBL_A@2] → [WR:TBL_A@2])。
// 変換対象は 全角英数字・_$#. のみで、 かな / 漢字 / 長音 (ー) / 半角カナ 等の
// 日本語文字は対象外なので、 日本語テーブル名は壊れない。
// ★テスター指摘 No.130: 実テーブル名そのものが全角英数字を含む場合 (例: 受注ヘッダ2)、
// 半角化した名前は DB カタログと一致せず 「DB未検出」 になっていた。 半角化前の名前も
// tableRaw として保持し、 呼び出し側 (scanTableRefs) で照合のフォールバック候補にする。
// 変換は 1 文字 → 1 文字なので s と s0 の文字位置は完全に一致する
// (= マッチ位置 m.index / 長さ m[0].length で s0 側の同じ区間を切り出せる)。
// ★2026-10-11: / - も半角化する (@接続名 の jdbc/SapGateway のような名前を全角で打ったとき用。
// テーブル名側では '/' '-' は元々不可なので受理範囲は変わらない)。
var s = s0.replace(/[A-Za-z0-9_$#./-]/g, function (c) {
return String.fromCharCode(c.charCodeAt(0) - 0xFEE0);
});
// テーブル名 1 文字ぶんの文字クラス。 日本語テーブル名を受理するため
// 「使える文字の列挙」 ではなく 「使えない文字の除外」 で定義する
// (_collectSqlTableNames の識別子パターンが非 ASCII を通すのと同じ思想)。
// 除外するもの:
// ・半角: 英数字 _ $ # . 以外すべて (制御文字 / 空白 / カンマ / [ ] : @ /
// ハイフン / 引用符 / % & ( ) 等 — タグ構文文字と SQL 記号を排除)
// ・非 ASCII: 空白・区切り・括弧・引用符の類のみ
// (U+00A0 / 一般句読点 U+2000-206F / 、。〃〄 / 〈〉「」【】〜 等 U+3008-3020 /
// 中黒 ・ / 全角記号 !-/ :-@ [-` {-・)
// → カンマ列挙 ([R:T1,T2] / [R:T1,T2]) と 名前中の空白は 従来どおり不成立。
var TCH = '[^\\x00-\\x22\\x25-\\x2D\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F' +
'\\u00A0\\u2000-\\u206F\\u3000-\\u3004\\u3008-\\u3020\\u30FB' +
'\\uFF01-\\uFF0F\\uFF1A-\\uFF20\\uFF3B-\\uFF40\\uFF5B-\\uFF65]';
// 先頭文字だけは '.' を許さない (従来どおり [R:.TBL] は不成立)
// ★2026-10-11: @ の後ろは 接続番号 (1〜2 桁) か 接続名 (英字始まり、 英数字 _ . / - 。
// talonJdbc.properties の N.jndi.name = jdbc/SapGateway など)。 名前は dbName に入れ、
// 接続番号への解決は呼び出し側 (_resolveNoteTagDbName) で行う (このパーサは純関数のまま)。
var re = new RegExp('\\[\\s*(WR|RW|R|W)\\s*:\\s*((?!\\.)' + TCH + TCH + '*)' +
'\\s*(?:@\\s*(\\d{1,2}|[A-Za-z][A-Za-z0-9_./\\-]*))?\\s*\\]', 'gi');
var m;
while ((m = re.exec(s)) !== null) {
var mode = m[1].toUpperCase();
if (mode === 'RW') mode = 'WR';
var dbTok = (m[3] === undefined || m[3] === null) ? null : String(m[3]);
var db = null, dbName = null;
if (dbTok !== null) {
if (/^\d{1,2}$/.test(dbTok)) {
db = String(Number(dbTok));
if (db === '0') db = ''; // @0 = 主 TALON DB の明示指定
} else {
dbName = dbTok; // @接続名 (大文字小文字はそのまま。 解決時に区別しない)
}
}
// 原文 (全角英数字を半角化する前) のテーブル名を s0 の同じ位置から切り出す。
// s と s0 は 1 文字 → 1 文字の置換しかしていないため 長さ・位置が完全に一致する。
// タグ内のテーブル名の開始位置は 「':' の後に現れる m[2]」 で特定する。
var tblRaw = m[2];
try {
var colonPos = m[0].indexOf(':');
var tblOff = m[0].indexOf(m[2], colonPos + 1);
if (tblOff >= 0) {
tblRaw = s0.substring(m.index + tblOff, m.index + tblOff + m[2].length);
}
} catch (eRaw) { /* 切り出し失敗時は 正規化名をそのまま原文候補とする */ }
out.push({ mode: mode, table: m[2].toUpperCase(), tableRaw: String(tblRaw).toUpperCase(),
db: db, dbName: dbName, raw: m[0] });
}
return out;
}
// ★2026-10-11: 備考タグの @接続名 → 接続番号。
// talonJdbc.properties の `N.jndi.name=jdbc/XXX` (N = 1..15) と主 DB の `jndi.name=jdbc/TalonDb` を読み、
// 名前 (小文字、 jdbc/ を除いた形も) → 接続番号 ('' = 主 DB) の表にする。 パース部は純関数 (tests/test_pure_funcs.py)。
function _parseTalonJdbcConnNames(text) {
var map = {};
if (!text) return map;
var lines = String(text).split(/\r\n|\r|\n/);
for (var i = 0; i < lines.length; i++) {
var ln = lines[i].replace(/^\s+|\s+$/g, '');
if (!ln || ln.charAt(0) === '#' || ln.charAt(0) === '!') continue;
var m = /^(?:(\d{1,2})\s*\.\s*)?jndi\.name\s*[=:]\s*(.+)$/i.exec(ln);
if (!m) continue;
var no = m[1] ? String(Number(m[1])) : '';
var key = m[2].replace(/\s+$/, '').toLowerCase();
if (!key) continue;
if (!map.hasOwnProperty(key)) map[key] = no;
var shortKey = key.replace(/^jdbc\//, '');
if (shortKey !== key && !map.hasOwnProperty(shortKey)) map[shortKey] = no;
}
return map;
}
var _talonJdbcConnNamesCache = null; // { at: ミリ秒, map: {} } — 5 分で読み直す (設定変更は再起動が要るので十分)
function _talonJdbcConnNames() {
var now = new Date().getTime();
if (_talonJdbcConnNamesCache && (now - _talonJdbcConnNamesCache.at) < 300000) return _talonJdbcConnNamesCache.map;
var map = {};
try {
var cl = Java.type('java.lang.Thread').currentThread().getContextClassLoader();
var url = cl.getResource('talonJdbc.properties');
if (url) {
var bytes = Java.type('java.nio.file.Files').readAllBytes(new (Java.type('java.io.File'))(url.toURI()).toPath());
map = _parseTalonJdbcConnNames(String(new (Java.type('java.lang.String'))(bytes, 'UTF-8')));
}
} catch (e) {
try { TALON.getLogger().writeWarn('[TFC] talonJdbc.properties の接続名の読取に失敗: ' + e); } catch (ig) {}
}
_talonJdbcConnNamesCache = { at: now, map: map };
return map;
}
function _resolveNoteTagDbName(name) { // 戻り値: '1'..'15' / '' (主 DB) / null (未登録)
if (!name) return null;
var map = _talonJdbcConnNames();
var k = String(name).toLowerCase();
if (map.hasOwnProperty(k)) return map[k];
var k2 = k.replace(/^jdbc\//, '');
if (map.hasOwnProperty(k2)) return map[k2];
return null;
}
// 備考タグのテーブル名解決 (★テスター指摘 No.130)。
// タグは IME 対策で全角英数字を半角化してからパースするため、 実テーブル名そのものが
// 全角英数字を含む場合 (例: 受注ヘッダ2) は 半角化した名前が DB カタログと一致せず
// 「DB未検出」 (リンク無し) になっていた。
// 照合順: ① 正規化名 (半角化) → ② 原文名。 ① で実在が確認できたときは 従来どおり
// ① を使うので、 既存の出力は一切変わらない。 ② でだけ実在するときに限り カタログの
// 実名 (= 原文側) を採用して、 実在照合・リンク・ER 図の和集合に載せる。
// どちらも実在しない場合も 従来どおり ① (= 「DB未検出」表示は正規化名のまま)。
var _noteTagNameCache = {};
function _resolveNoteTagTableName(norm, raw, accessDb) {
if (!raw || raw === norm) return norm;
var ck = String(accessDb == null ? '' : accessDb) + '|' + norm + '|' + raw;
if (_noteTagNameCache.hasOwnProperty(ck)) return _noteTagNameCache[ck];
var resolved = norm;
var conn = null;
try {
var dbType;
if (accessDb) {
// ★テスター指摘 No.133: 照合は タグが帰属する接続先のカタログだけで行う。
// 接続先が未設定/取得失敗のときに 主 DB で照合すると、 指定先に無いテーブルを
// 主 DB の名前で解決してしまい 帰属と食い違う (= 主 DB へリンクされる) ため、
// 照合そのものを諦めて 正規化名のまま返す (実在照合側も 「DB未検出」 になる)。
try { conn = TALON.getOtherDBConn(String(accessDb)); }
catch (eOc) {
try { TALON.getLogger().writeInfo('[TFC] 備考タグ 照合: getOtherDBConn(' + accessDb +
') 失敗 → 原文フォールバック照合をスキップ: ' + eOc); } catch (ig0) {}
conn = null;
}
if (!conn) {
_noteTagNameCache[ck] = norm;
return norm;
}
}
if (conn) dbType = TFC.detectDbTypeByConn(conn);
// 主 DB は _procDbType (probe トランザクションを張らない安全な判定) を使う
else dbType = _procDbType();
dbType = String(dbType || '').toLowerCase();
if (dbType === 'postgresql') dbType = 'postgres';
if (dbType.indexOf('mysql') === 0) dbType = 'mysql';
if (dbType.indexOf('cdata') === 0) dbType = 'cdata';
if (dbType && dbType !== 'unknown') {
// 指定順 (正規化名 → 原文名) がそのまま優先順位になる
var meta = _fetchErMeta([norm, raw], dbType, false, conn);
if (meta && meta.tables && meta.tables.length > 0) {
resolved = TFC.s(meta.tables[0].name) || norm;
}
}
} catch (eR) {
try { TALON.getLogger().writeWarn('[TFC] 備考タグ テーブル名の原文フォールバック照合をスキップ (' +
norm + ' / ' + raw + '): ' + eR); } catch (ig) {}
resolved = norm;
}
// 外部 DB 接続はプールへ返却 (読み取りのみなので rollback で副作用なし)
if (conn && typeof TalonDbUtil !== 'undefined') {
try { TalonDbUtil.rollback(conn); } catch (eRb) {}
}
_noteTagNameCache[ck] = resolved;
return resolved;
}
// BODY_SQL / TITLE_SQL / CHR_TEXT (JavaScript) / ストアドプロシージャ本体 を走査してテーブル参照を抽出
// 返り値: { read: [{table, src}], write: [{table, src}] }
// src は出典 (例: "BLOCK1.BODY_SQL", "0S100/UPDATE_BEFORE", "プロシージャ XXX" 等)
// src 内で同じ table が read/write 両方に該当する場合は両方に登録
// - 読み込み: FROM <T>, JOIN <T>
// - 書き込み: INSERT INTO <T>, UPDATE <T> SET, DELETE FROM <T>, MERGE INTO <T>
function scanTableRefs(ctx) {
// map 構造: { tableName: { srcs: {src1: true}, seqs: {seq1: true, seq2: true} } }
// seqs は 複数DB接続 (§5.20) の ACCESS_DB 紐付けに使う。 同一テーブルが複数ブロック
// から参照されると 複数 FUNC_SEQ が記録され、 各 FUNC_SEQ の ACCESS_DB 設定で接続先
// を解決する。 同一テーブルが異なる DB 接続から参照されるケースもあり得る (= ER メタ
// 取得は ACCESS_DB ごとに分離して呼び出す)。
var read = {}, write = {};
function pushTbl(map, table, src, funcSeq, jsDbs) {
if (!table) return;
var t = String(table).toUpperCase();
var skip = { 'DUAL': 1, 'SELECT': 1, 'WHERE': 1, 'AND': 1, 'OR': 1, 'NULL': 1,
'TRUE': 1, 'FALSE': 1, 'TABLE': 1, 'SET': 1, 'VALUES': 1, 'AS': 1, 'BY': 1,
'ON': 1, 'IN': 1, 'EXISTS': 1, 'CASE': 1, 'WHEN': 1, 'THEN': 1, 'END': 1, 'ELSE': 1 };
if (skip[t]) return;
if (!map[t]) map[t] = { srcs: {}, seqs: {}, jsDbs: {}, srcInfo: {} };
map[t].srcs[src] = true;
// 出典 (src) 単位の接続情報も保持 (No.27: 依存関係タブで同名テーブルを接続先ごとに
// 別ボックス表示するため、 どの出典がどの接続先へのアクセスかを後で解決できるようにする)
if (!map[t].srcInfo[src]) map[t].srcInfo[src] = { seqs: {}, jsDbs: {} };
if (funcSeq !== undefined && funcSeq !== null && funcSeq !== '') {
map[t].seqs[String(funcSeq)] = true;
map[t].srcInfo[src].seqs[String(funcSeq)] = true;
}
if (jsDbs && jsDbs.length > 0) {
for (var ji = 0; ji < jsDbs.length; ji++) {
map[t].jsDbs[String(jsDbs[ji])] = true;
map[t].srcInfo[src].jsDbs[String(jsDbs[ji])] = true;
}
}
}
// SQL 文字列を走査してテーブル参照を抽出。
// ・コメント / 文字列リテラルは除去済テキストに対して regex を当てる
// ・CTE / 派生表エイリアス (WITH SUB AS (...) 等) は物理テーブルから除外
// ・FROM/JOIN は直後に '(' が来るケース (括弧付き結合) にも対応 ([\s(]+)
function scanSql(text, src, funcSeq, jsDbs) {
if (!text) return;
// 共通コアで {read, write} (UPPER 名) を抽出し、 各テーブルに同一 src を付与。
// (src/funcSeq/jsDbs は 1 つの BODY_SQL に対して定数)
var r = _collectSqlTableNames(text);
for (var i = 0; i < r.read.length; i++) pushTbl(read, r.read[i], src, funcSeq, jsDbs);
for (var w = 0; w < r.write.length; w++) pushTbl(write, r.write[w], src, funcSeq, jsDbs);
}
// JS コード (CHR_TEXT) を走査。 コメントを除去した後、 文字列リテラルのうち
// 「SQL らしい (DML キーワードを含む)」もののみ scanSql に回す。 これにより
// addMsg('...FROM clause.') のようなメッセージ文字列を テーブルと誤検出しない。
function scanJs(text, src, funcSeq, jsDbs) {
if (!text) return;
// '+' で連結された SQL リテラル (例: 'SELECT ...' + ' FROM TBL ' + ' WHERE ...') を
// 1 つに復元してから走査する (リテラル単位だと FROM 句のテーブルを取りこぼすため)。
var dmlRe = _dmlKeywordRe();
var groups = _joinJsSqlLiterals(text);
for (var gi = 0; gi < groups.length; gi++) {
if (!dmlRe.test(groups[gi])) continue;
scanSql(groups[gi], src, funcSeq, jsDbs);
}
}
// BODY_SQL / TITLE_SQL (FUNC_SQL)
for (var i = 0; i < _scanSizeOf(ctx.sql); i++) {
var sq = ctx.sql[i];
var seq = TFC.s(sq['FUNC_SEQ']);
var sortNo = TFC.s(sq['SORT']);
var blockNo = (seq === '-1') ? (_scanLang === 'en' ? 'Whole function' : '機能全体') : ('BLOCK' + (Number(sortNo) + 1));
scanSql(TFC.s(sq['BODY_SQL']), blockNo + '.BODY_SQL', seq, null);
scanSql(TFC.s(sq['TITLE_SQL']), blockNo + '.TITLE_SQL', seq, null);
}
// CHR_TEXT (JavaScript エンジン / 各種コード)
// ★ 5.20.10 対応: JS コード内の DB 接続取得呼び出しを検出して、 後続のテーブル参照を
// 対応する接続先に紐付ける。 区間ベース:
// [先頭] ... [getOtherDBConn('1')] ... [getTalonDbConfig()] ... [末尾]
// 区間 0 (=既定) / 区間 1 (=DB=1) / 区間 2 (=主接続先)
// 各区間を独立にスキャンして 区間内のテーブルに DB タグを付与する。
// (1 ブロックに複数 DB を叩く JS でも 正確に対応関係を捕捉)
// テスター指摘 No.30 の接続先ルール:
// TALON.getOtherDBConn(X) → 複数DB接続先 X ('1'..'15')
// TALON.getTalonDbConfig() → 主接続先 ('')
// TALON.getDbConfig() → 既定 (機能レベルJS=機能設定 DB接続先 /
// ブロックJS=ブロック SELECT式 DB接続先 / 空欄=主)
// = seqs 経由の _resolveAccessDb と同じ解決
// ★分解の実体は _analyzeJsConnSegments (No.43: コメント除去→分割 / No.30 残:
// 変数バインディング解決で「リテラル宣言が接続呼出より前」の書き方に対応)
var dmlReJs = _dmlKeywordRe();
for (var j = 0; j < _scanSizeOf(ctx.optn); j++) {
var o = ctx.optn[j];
var ct = TFC.s(o['CHR_TEXT']);
if (ct.length === 0) continue;
var oSeq = TFC.s(o['FUNC_SEQ']);
var src = TFC.s(o['FUNC_KBN']) + (TFC.s(o['COL_NAME']) ? '/' + TFC.s(o['COL_NAME']) : '') +
' (FUNC_SEQ=' + oSeq + ')';
var jsParts = _analyzeJsConnSegments(ct);
// 変数経由で接続に帰属した SQL。 db=null は「既定接続先」(= jsDbs を付けず seqs 経由で
// 解決)、 db='' は「主接続先 明示」。 明示接続は seqs を記録しない (二重帰属防止)。
for (var rvi = 0; rvi < jsParts.resolved.length; rvi++) {
var rv = jsParts.resolved[rvi];
if (!dmlReJs.test(rv.sql)) continue;
if (rv.db != null) scanSql(rv.sql, src, null, [rv.db]);
else scanSql(rv.sql, src, oSeq, null);
}
// 残テキストの区間分割スキャン (接続呼出の後にリテラルを直接書く書き方)
for (var ci = 0; ci < jsParts.segments.length; ci++) {
var c = jsParts.segments[ci];
if (c.db != null) scanJs(c.text, src, null, [c.db]);
else scanJs(c.text, src, oSeq, null);
}
}
// TALON STD 機能の暗黙の DB 書込み: UPDATE_TABLE (機能ブロックの 更新対象テーブル)。
// TLN_M_GENERAL_APP に FUNC_KBN='UPDATE_TABLE' で更新先テーブルが設定される
// (manual §5.20.8/9 のブロック設定参照)。 SQL テキストには出てこないため scan() では
// 捕捉できず、 ここで明示的に追加。 ACCESS_DB 紐付けにも FUNC_SEQ を持たせる。
if (ctx.app) {
for (var ai = 0; ai < _scanSizeOf(ctx.app); ai++) {
var aRec = ctx.app[ai];
var aKbn = TFC.s(aRec['FUNC_KBN']);
if (aKbn !== 'UPDATE_TABLE') continue;
var aTbl = TFC.s(aRec['VALUE']);
if (!aTbl) continue;
var aSeq = TFC.s(aRec['FUNC_SEQ']);
var aSrc = aKbn + ' (FUNC_SEQ=' + aSeq + ')';
pushTbl(write, aTbl, aSrc, aSeq);
}
}
// ストアドプロシージャ参照: 本体ソースを取得して 読み/書き テーブルを抽出。
// プロシージャ名の格納箇所 (DB設定マスタ準拠):
// ・TLN_M_GENERAL_ITEM_OPTN FUNC_KBN='BUTTON_BAT' AND FLAG='0' → CHR1
// ・TLN_M_GENERAL_APP FUNC_KBN=PL_SQL_NAME系 → VALUE (確定/明細/検索 の前後)
try {
var procRefs = _collectProcRefs(ctx);
var procNames = Object.keys(procRefs);
for (var pk = 0; pk < procNames.length; pk++) {
var pname = procNames[pk];
var psrc = _getProcSource(pname);
if (psrc) scanSql(psrc, (_scanLang === 'en' ? 'Procedure ' : 'プロシージャ ') + pname, procRefs[pname].seq, null); // ★No.294: 出典の文言は出力言語 (備考タグと同じ)
}
} catch (eProc) {
try { TALON.getLogger().writeWarn('[TFC] プロシージャ参照スキャン失敗: ' + eProc); } catch (ig) {}
}
// 他機能呼出 (OTHER_FUNC): 呼出先ブロックが更新するテーブルを 書き込み として追加。
// 呼出元ブロックで登録/更新/削除が実行されると、 呼出先ブロックの UPDATE_TABLE にも
// INSERT/UPDATE/DELETE/MERGE が連動実行される (manual 5.13.1 「他機能を呼び出しDB更新する」)。
// ITEM_OPTN FUNC_KBN='OTHER_FUNC': CHR2=呼出先機能ID, NUM1=呼出先ブロック FUNC_SEQ,
// CHR3/CHR4/CHR5=登録/更新/削除時モード (いずれも未選択なら呼出先は実行されない)。
try {
if (ctx.optn) {
for (var ofi = 0; ofi < _scanSizeOf(ctx.optn); ofi++) {
var ofo = ctx.optn[ofi];
if (TFC.s(ofo['FUNC_KBN']) !== 'OTHER_FUNC') continue;
var ofMode = TFC.s(ofo['CHR3']) || TFC.s(ofo['CHR4']) || TFC.s(ofo['CHR5']);
if (!ofMode) continue; // 登録/更新/削除いずれも未選択 = 呼出先処理なし
var ofFid = TFC.s(ofo['CHR2']);
if (!ofFid) continue;
var ofSeqRaw = TFC.s(ofo['NUM1']);
var ofSeq = (ofSeqRaw === '') ? '0' : String(Number(ofSeqRaw)); // "1.0" → "1"
var srcSeq = TFC.s(ofo['FUNC_SEQ']);
var cb = _getCalledBlockRefs(ofFid, ofSeq);
var ofSrc = (_scanLang === 'en' ? 'Other-function call ' : '他機能呼出 ') + ofFid + (cb.title ? ' / ' + cb.title : ''); // ★No.294: 出典の文言は出力言語
// 呼出先ブロックの UPDATE_TABLE / BODY_SQL / JS で参照するテーブルを
// 呼出元の 書き込み・読み取り として取り込む (1 階層のみ)。
for (var ocw = 0; ocw < cb.write.length; ocw++) pushTbl(write, cb.write[ocw], ofSrc, srcSeq);
for (var ocr = 0; ocr < cb.read.length; ocr++) pushTbl(read, cb.read[ocr], ofSrc, srcSeq);
}
}
} catch (eOf) {
try { TALON.getLogger().writeWarn('[TFC] 他機能呼出 参照スキャン失敗: ' + eOf); } catch (ig) {}
}
// 備考欄の手動依存タグ ([R:TBL] / [W:TBL@2] / [WR:S1.TBL] — _collectNoteDepTags 参照)。
// @N 無し → FUNC_SEQ=-1 として push (= 機能レベル ACCESS_DB → 主 DB の順で解決)
// @N 有り → jsDbs へ明示 DB として push (既定接続先へは紐付けない)
// ★No.130: 実テーブル名が全角英数字を含む場合は 原文の名前でも実在照合する
// (_resolveNoteTagTableName)。 照合先の接続先は @N 明示 → 機能レベル ACCESS_DB →
// 主 DB の順 (= 出典の帰属先と同じ) で、 @N の帰属 (jsDbs) は名前に依らず不変。
try {
var noteTags = _collectNoteDepTags(ctx.func ? TFC.s(ctx.func['NOTE']) : '');
var ntFuncLevelDb = null; // 遅延解決 (フォールバックが必要なタグがある時だけ引く)
for (var nti = 0; nti < noteTags.length; nti++) {
var ntg = noteTags[nti];
var ntDb = ntg.db; // '1'..'15' / '' (@0) / null (省略)
var ntNameNote = '';
if (ntg.dbName) { // ★2026-10-11: @接続名 (talonJdbc.properties の N.jndi.name) → 接続番号
var ntResolved = _resolveNoteTagDbName(ntg.dbName);
if (ntResolved === null) {
// 未登録の名前は 機能の DB 接続先 (省略時と同じ) に帰属させ、 出典に注記して気付けるようにする
ntNameNote = (_scanLang === 'en') ? ' (connection name not found: ' + ntg.dbName + ')'
: ' (接続名 ' + ntg.dbName + ' は未登録)';
try { TALON.getLogger().writeWarn('[TFC] 備考タグ ' + ntg.raw + ': 接続名 ' + ntg.dbName +
' が talonJdbc.properties (N.jndi.name) に無い → 機能の DB 接続先として扱う'); } catch (ig2) {}
} else {
ntDb = ntResolved;
}
}
var ntSrc = (_scanLang === 'en' ? 'Note tag ' : '備考タグ ') + ntg.raw + ntNameNote;
var ntSeq = (ntDb === null) ? '-1' : null;
var ntDbs = (ntDb === null) ? null : [ntDb];
var ntTbl = ntg.table;
if (ntg.tableRaw && ntg.tableRaw !== ntg.table) {
if (ntFuncLevelDb === null) {
ntFuncLevelDb = '';
try { ntFuncLevelDb = _collectAccessDbMap(ctx).funcLevel || ''; } catch (eAd) {}
}
ntTbl = _resolveNoteTagTableName(ntg.table, ntg.tableRaw,
(ntDb === null) ? ntFuncLevelDb : ntDb);
}
if (ntg.mode.indexOf('R') >= 0) pushTbl(read, ntTbl, ntSrc, ntSeq, ntDbs);
if (ntg.mode.indexOf('W') >= 0) pushTbl(write, ntTbl, ntSrc, ntSeq, ntDbs);
}
} catch (eNote) {
try { TALON.getLogger().writeWarn('[TFC] 備考タグ 参照スキャン失敗: ' + eNote); } catch (ig) {}
}
function toArr(map) {
var arr = [];
var keys = Object.keys(map);
for (var k = 0; k < keys.length; k++) {
var entry = map[keys[k]];
// srcInfo は {src: {seqs: [...], jsDbs: [...]}} の配列化形式に変換
var srcInfoOut = {};
var siKeys = Object.keys(entry.srcInfo || {});
for (var s2 = 0; s2 < siKeys.length; s2++) {
var si = entry.srcInfo[siKeys[s2]];
srcInfoOut[siKeys[s2]] = {
seqs: Object.keys(si.seqs || {}),
jsDbs: Object.keys(si.jsDbs || {})
};
}
arr.push({
table: keys[k],
srcs: Object.keys(entry.srcs || entry),
seqs: Object.keys(entry.seqs || {}),
jsDbs: Object.keys(entry.jsDbs || {}),
srcInfo: srcInfoOut
});
}
arr.sort(function (a, b) { return a.table < b.table ? -1 : a.table > b.table ? 1 : 0; });
return arr;
}
return { read: toArr(read), write: toArr(write) };
}
// 機能内の ACCESS_DB (複数DB接続) 設定を集約。
// manual §5.20.8 (機能アプリケーションタブ) + §5.20.9 (ブロック SELECT 式タブ)
//
// 優先順位:
// 1. ブロック設定 (FUNC_SEQ=N, N>=0)
// 2. 機能設定 (FUNC_SEQ=-1) ← なければ "" (= 主 TALON DB)
// ※ TLN_M_GENERAL_APP に FUNC_KBN='ACCESS_DB' で VALUE='1'..'15' (talonJdbc.properties
// に登録した接続番号) が格納されている。
//
// 戻り値: { funcLevel: '1'|'', byBlock: { '0': '1', '1': '2', ... } }
function _collectAccessDbMap(ctx) {
var funcLevel = '';
var byBlock = {};
if (!ctx || !ctx.app) return { funcLevel: funcLevel, byBlock: byBlock };
for (var i = 0; i < _scanSizeOf(ctx.app); i++) {
var a = ctx.app[i];
if (TFC.s(a['FUNC_KBN']) !== 'ACCESS_DB') continue;
var seq = TFC.s(a['FUNC_SEQ']);
var val = TFC.s(a['VALUE']);
if (!val) continue;
if (seq === '-1') funcLevel = val;
else byBlock[seq] = val;
}
return { funcLevel: funcLevel, byBlock: byBlock };
}
// 指定 FUNC_SEQ で使われる ACCESS_DB を解決。
// テスター指摘 No.29: 機能レベル (アプリケーションタブ) の DB接続先はブロックへ波及しない。
// ブロック (FUNC_SEQ>=0) の SELECT式 DB接続先が空欄なら 主接続先 ('') にアクセスされる。
// 機能レベル設定が適用されるのは 機能レベル処理 (FUNC_SEQ=-1: 機能レベル JS /
// 備考タグ @N 省略時 等) のみ。
function _resolveAccessDb(accessDbInfo, funcSeq) {
if (!accessDbInfo) return '';
var key = String(funcSeq);
if (key === '-1') return accessDbInfo.funcLevel || '';
if (accessDbInfo.byBlock && accessDbInfo.byBlock.hasOwnProperty(key)) return accessDbInfo.byBlock[key];
return '';
}
TFC.scanConfigure = function (opts) {
opts = opts || {};
_scanSel = opts.select || null;
_scanLang = opts.lang || 'ja';
_scanDbTypeOverride = TFC.s(opts.dbType || '');
_procSrcCache = {};
_procDbTypeCache = null;
_calledBlockCache = {};
_noteTagNameCache = {};
};
// '?' プレースホルダを値リテラルへ展開 (0R100 用 — PS が使えない文脈で TFC.selectU に
// 渡す SQL を作る)。文字列リテラル内の '?' は展開しない。「'」は二重化エスケープ。
// SQL 文字列リテラルのエスケープ (DB 方言対応)。 「'」は SQL 標準どおり二重化。
// ★MySQL はリテラル内で「\」をエスケープ文字として扱う (NO_BACKSLASH_ESCAPES 無効が既定)
// ため、「\」も二重化しないと `'FUNCID_TEST_\'` のように文字列が閉じず SQL 文法エラー
// になる (テスター指摘 No.78 = MySQL 環境で FUNC_ID にバックスラッシュを含む機能を検索)。
// Oracle/PostgreSQL/SQLServer は「\」を通常文字として扱うので二重化してはならない (値が壊れる)。
TFC.sqlLitEscape = function (v, dbType) {
var s = String(v);
if (/mysql/i.test(String(dbType || ''))) s = s.replace(/\\/g, '\\\\');
return s.replace(/'/g, "''");
};
TFC.scanInlineParams = function (sql, params) {
var s = String(sql || '');
var out = '';
var inStr = false;
var pi = 0;
for (var i = 0; i < s.length; i++) {
var c = s.charAt(i);
if (inStr) { out += c; if (c === "'") inStr = false; continue; }
if (c === "'") { out += c; inStr = true; continue; }
if (c === '?') {
var v = (params && pi < params.length) ? params[pi] : null;
pi++;
if (v == null) out += 'NULL';
else if (typeof v === 'number') out += String(v);
else out += "'" + TFC.sqlLitEscape(v, _scanDbTypeOverride) + "'";
continue;
}
out += c;
}
return out;
};
TFC.scanTableRefs = scanTableRefs;
TFC.collectAccessDbMap = _collectAccessDbMap;
TFC.resolveAccessDb = _resolveAccessDb;
TFC.stripJsComments = _stripJsComments;
TFC.getProcSource = _getProcSource;
TFC.collectProcRefs = _collectProcRefs;
TFC.getCalledBlockRefs = _getCalledBlockRefs;
TFC.collectNoteDepTags = _collectNoteDepTags;
TFC.resolveNoteTagDbName = _resolveNoteTagDbName; // 物理属性名の @接続 (2026-10-13) も同じ解決を使う
TFC.buildSeqBlockMap = _buildSeqBlockMap;
TFC.isCodebookCodeKbn = _isCodebookCodeKbn;
TFC.pushSqlTablesFromJs = _pushSqlTablesFromJs;
TFC.readClobVal = _readClobVal;
// export
global.TFC = TFC;
return TFC;
})(this);
≣ サーバJS ライブラリTLN_FUNC_DOC_ER TALON機能設計書出力 ERモデル層ライブラリ (a5er/SVG/変換) 248559字
// TLN_FUNC_DOC_ER: TALON機能設計書出力 ERモデル層 共通サーバ側JS (Ver1.0.7〜)
// LIBRARY_CODE: TLN_GENERAL_JAVASCRIPT_ENGINE / KEY_CODE: TLN_FUNC_DOC_ER / 公開オブジェクト: TFE
//
// 役割: .a5er の読み書き / ER 図の SVG 描画 / 他ツールの形式 (DDL / SI Object Browser ER .edm / Visio .vsdx / astah .asta) → .a5er 変換。
// ・製品本体 (TLN_FUNC_DOC_COMMON = TFC) から独立した ES5 の純関数だけで書く (Java.type / TALON.* / TFC.* を使わない)。
// 同じコードが Nashorn (サーバ) と Node (回帰テスト) で動く (ブラウザで動く ES5 のまま保つ)。
// ・本体は実行時に TFE.* を呼ぶ (読み込み順に依存しない)。 本体側の TFC.parseA5er / renderA5erToSvg / edmConvToA5er 等は TFE への委譲。
// ・機能のスクリプト設定 (ライブラリ) に TLN_FUNC_DOC_COMMON と一緒に列挙して読み込む
// (設計書出力の確定前 JS / EDM メンテナンスの確定後 JS / SETUP の処理実行。 tools/setup_er_library_refs.py)。
// ・版: TFE.VERSION は改善のたびに上げる (本体とは独立に差し替えられる)。 TFE.API は本体との取り決めの版
// (本体の _tfe() が最低版を確認する。 互換を壊す変更で上げる)。
//
// 提供API (本体の TFC と同じ名前 + 短い別名):
// TFE.parseA5er(text) .a5er → 属性カタログ用 {entities, domainInfos, domainDefs}
// TFE.parseA5erModel(text) .a5er → 描画モデル (entities / relations / subtypes / views / shapes …)
// TFE.renderA5erToSvg(model, reg) 描画モデル → {svg, …} (設計書の EDM.html / EDM メンテナンスのプレビュー)
// TFE.edmPreviewSvg(svg, title, lang) プレビュー SVG (ズーム/パンのビューア埋め込み)
// TFE.erToA5er(meta) 物理 DB のメタ (設計書の ER 図) → .a5er
// TFE.edmConvToA5er(input, opts) 他形式 (OBER XML / Visio JSON / astah {asta:1, bytes}) → {a5er, stats, warnings}。 ★Ver1.0.22: DDL 文字列は対応外 (throw)
// TFE.a5erContentPages(model) / TFE.groupFks(fks)
// TFE.vsdxUnzip(buf, re, raw) / TFE.vsdxBundle(name, files) / TFE.vsdxParse(bundle) / TFE.astaDeser(bytes) / TFE.astaParse(input) / TFE.oberParse(xml)
(function (global) {
'use strict';
var TFE = { VERSION: '1.0.9.1', API: 1 };
// ============================================================
// 本体 (TFC) に依存しないための最小ヘルパ (実装は TFC.s / escapeHtml / escapeAttr / t と同じ)
// ============================================================
function _erS(v) {
if (v == null) return '';
var s = String(v);
// NUM 系列の DB エンジン差を正規化:
// Oracle : "1"
// SQL Server / MySQL : "1.000000" (BigDecimal scale が CSV 取込時に保持される)
// → 整数化可能なら "1" に揃える。 比較 (=== '1') が DB 横断で動くようにする。
// 実数値 ("1.5" 等) は変更しない。
if (s.length > 2 && s.indexOf('.') > 0 && /^-?\d+\.0+$/.test(s)) {
return s.replace(/\.0+$/, '');
}
return s;
}
function _erEsc(s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function _erEscAttr(s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
var _erLabels = {
// ---- EDM メンテナンスのプレビュー SVG (Ver1.0.4): 直接表示時の操作ボタン tooltip ----
'edmPrev.zoomIn': { ja: '拡大', en: 'Zoom in' },
'edmPrev.zoomOut': { ja: '縮小', en: 'Zoom out' },
'edmPrev.fit': { ja: '全体表示', en: 'Fit to window' },
'edmPrev.natural': { ja: '原寸', en: 'Actual size' },
'edmPrev.allPages': { ja: '全ページ', en: 'All pages' },
};
function _erT(key, lang) {
var entry = _erLabels[key];
if (!entry) return key;
var l = (lang === 'en') ? 'en' : 'ja';
return entry[l] != null ? entry[l] : (entry.ja != null ? entry.ja : key);
}
TFE.s = _erS; TFE.escapeHtml = _erEsc; TFE.escapeAttr = _erEscAttr; TFE.t = _erT;
// ============================================================
// .a5er (A5:SQL Mk-2 ネイティブ) の軽量パーサ — 唯一の正 (Ver0.53)
//
// Ver0.52 までは 「宿題一覧の突合用 (型欄のドメイン名)」 と 「メンテ画面の
// 入力補助用 (エンティティ×属性名)」 で 2 つのパーサが並存し、 二重管理に
// なっていた。 両者が必要とする値は同じ Field= 行から取れるので 1 つに統合する。
//
// 戻り値 (a5er でなければ null):
// { entities: [{ nm: LName, cd: PName,
// attrs: [{ nm: 論理属性名, cd: 物理属性名, domain: 型欄 }] }],
// domainInfos: [ユーザー定義ドメインの定義名, ...] }
//
// ★仕様メモ (Ver0.52 までの 2 実装の挙動を維持するための約束):
// - Field= は CSV。 toks[0]=論理名 / toks[1]=物理名 / toks[2]=型欄
// - 型欄の先頭 '*' は A5M2 のユーザー定義ドメイン参照 → 剥がす
// - LName が空のエンティティも entities に載せる (型欄の集合は失わない)。
// 「エンティティ名が要る用途」 (属性カタログ) 側で捨てること
// - DomainInfo= は [Manager] のユーザー定義ドメイン定義 (名前 = dtoks[0])
// ============================================================
function _a5erUnesc(v) {
return String(v || '')
.replace(/\\\\/g, '\x00').replace(/\\n/g, '\n').replace(/\\t/g, '\t')
.replace(/\\Q/g, '"').replace(/\\q/g, "'").replace(/\x00/g, '\\');
}
function _a5erCsv(s) {
var out = [], i = 0, n = s.length;
while (i < n) {
if (s.charAt(i) === '"') {
i++; var t = '';
while (i < n) {
var ch = s.charAt(i);
if (ch === '"') { if (s.charAt(i + 1) === '"') { t += '"'; i += 2; continue; } i++; break; }
t += ch; i++;
}
out.push(t);
while (i < n && s.charAt(i) !== ',') i++;
if (i < n) i++;
} else {
var j = s.indexOf(',', i);
if (j < 0) { out.push(s.substring(i)); break; }
out.push(s.substring(i, j)); i = j + 1;
}
}
for (var u = 0; u < out.length; u++) out[u] = _a5erUnesc(out[u]);
return out;
}
function _a5erNorm(s) {
return String(s == null ? '' : s).replace(/\s+/g, ' ').replace(/^ | $/g, '');
}
// ★Ver1.0.11: 型欄 (Field の型トークン) は「定義域」だけを表す。 `*名前` = A5M2 のユーザー定義ドメイン参照 (DomainInfo の型・
// コメントを補完)、 それ以外はデータ型の直書き。 業務データ辞書との結び付きは辞書側の EDM 属性宣言
// (TLN_M_FUNC_DOMAIN_ATTR.EDM_ATTR) だけで行い、 型欄を辞書名として解釈しない (ユーザー決定 2026-09-24)。
TFE.parseA5er = _parseA5erCatalog;
function _parseA5erCatalog(text) {
if (!text) return null;
text = String(text).replace(/^/, '');
if (text.indexOf('A5:ER') < 0) return null; // .a5er 以外 (旧 drawio / SVG 等)
// domainDefs: 小文字名 → { nm, type, comment } (Ver1.0.5: DATA_TYPE / DOMAIN_COMMENT の元)
var res = { entities: [], domainInfos: [], domainDefs: {} };
var lines = text.split(/\r\n|\r|\n/);
var section = '', cur = null;
for (var i = 0; i < lines.length; i++) {
var ln = lines[i];
var st = ln.replace(/^\s+|\s+$/g, '');
if (st.charAt(0) === '[' && st.charAt(st.length - 1) === ']') {
if (cur) res.entities.push(cur);
section = st.substring(1, st.length - 1);
cur = (section === 'Entity') ? { nm: '', cd: '', attrs: [] } : null;
continue;
}
var eq = ln.indexOf('=');
if (eq < 0) continue;
var key = ln.substring(0, eq);
var val = ln.substring(eq + 1);
if (key === 'DomainInfo') {
var dts = _a5erCsv(val);
var dnm = _a5erNorm(dts[0] || '');
if (dnm) {
res.domainInfos.push(dnm);
res.domainDefs[dnm.toLowerCase()] = { nm: dnm, type: _a5erNorm(dts[1] || ''),
comment: String(dts[2] || '').replace(/^\s+|\s+$/g, '') };
}
continue;
}
if (!cur) continue;
if (key === 'LName') cur.nm = _a5erNorm(val);
else if (key === 'PName') cur.cd = _a5erNorm(val);
else if (key === 'Field') {
var toks = _a5erCsv(val);
if (String(toks[9] || '').toUpperCase() === 'DISABLE') continue; // ★Ver1.0.22 (No.221): 無効列 (A5M2 の既定で図に出ない) は属性カタログに入れない
var typ = _a5erNorm(toks[2] || '');
var isUser = false; // '*名前' = A5M2 のユーザー定義ドメイン参照 (DomainInfo に定義がある)
var dom = '';
if (typ.charAt(0) === '*') { dom = typ.substring(1).replace(/^\s+/, ''); isUser = true; }
cur.attrs.push({
nm: _a5erNorm(toks[0] || ''),
cd: _a5erNorm(toks[1] || ''),
domain: dom, // ツールのドメイン名 (定義域名。 参照でなければ空)
userDomain: isUser,
typeText: isUser ? '' : typ, // 型の直書き (定義域の型)
comment: _a5erUnesc(String(toks[6] || '')).replace(/^\s+|\s+$/g, '') // ★2026-10-02 (案 A): 属性のコメント (Field の 7 番目) → カタログの ATTR_COMMENT
});
}
}
if (cur) res.entities.push(cur);
return res;
}
// ============================================================
// A5:SQL Mk-2 (.a5er) の解析と SVG 描画 (Ver1.0.4 で update-before.server.js から移設)
//
// 設計書出力 (EDM.html / EDM.md) と EDM メンテナンスのプレビュー SVG が同じ描画を
// 使うため、 1 実装を共通JS に置き TFE.parseA5erModel / TFE.renderA5erToSvg で公開する。
// ★テキストは update-before.server.js にあったものを無変更で移した (golden 不変)。
// registry (EDM レジストリ) は省略可 — null ならリンク注入なしの素の図になる
// (プレビューはこちら)。 既存の TFC.parseA5er (属性カタログ用の軽量パーサ) とは別物。
// ============================================================
// 名前の正規化 (連続空白を 1 つに畳み前後を除く)。 update-before.server.js の _emNorm と同一
function _emNorm(s) {
return String(s == null ? '' : s).replace(/\s+/g, ' ').replace(/^ | $/g, '');
}
// 数値パース (空・非数値は null)。 SORT_NO / SEQ_NO 等の安定ソート用
function _emNum(v) {
if (v == null) return null;
var s = String(v).replace(/^\s+|\s+$/g, '');
if (s === '') return null;
var n = parseFloat(s);
return isNaN(n) ? null : n;
}
// .a5er テキストを解析。 戻り: { hasModel, entities:[{pname,lname,attrs:[{lname,pname,pk}],x,y,w,h}],
// relations:[{e1,e2,f1,f2}], byPName }
function _parseA5er(text) {
var res = { hasModel: false, entities: [], relations: [], subtypes: [], byPName: {},
// ★2026-07-31 A5M2 仕様対応の拡張 (テスター指摘 No.89/93/96/97):
domains: {}, // No.89: [Manager] DomainInfo — 名前(lower) → {name, type, comment, defCol}
pages: [], // No.93: [Manager] PageInfo のページ名 (定義順)
views: [], // No.96: [View]
shapes: [], // No.96: [Shape]
lines: [], // No.96: [Line]
comments: [], // No.96: [Comment]
viewFormat: '0', // IDEF1X 対応: [Manager] ViewFormat (0=IE / 1=IDEF1X)
pageMode: {}, pageBg: {}, // ★Ver1.0.22 (No.216〜221): PageInfo の表示モード (3 = 属性とデータ型) と背景色 (ページ名 → 値)
nonDepDash: false, showDisabled: false }; // [Manager] UseNondependenceDashLine (IE で非依存を破線) / ShowDisableAttributes
if (!text) return res;
text = text.replace(/^/, '');
if (text.indexOf('A5:ER') < 0 && text.indexOf('[Entity]') < 0) return res;
res.hasModel = true;
var lines = text.split(/\r\n|\r|\n/);
var cur = null, kind = null;
function commit() {
if (!cur) return;
if (kind === 'Entity') { res.entities.push(cur); if (cur.pname) res.byPName[cur.pname] = cur; }
else if (kind === 'Relation') res.relations.push(cur);
else if (kind === 'Subtype') { cur.isSub = true; res.subtypes.push(cur); if (cur.pname) res.byPName[cur.pname] = cur; }
else if (kind === 'View') res.views.push(cur);
else if (kind === 'Shape') res.shapes.push(cur);
else if (kind === 'Line') res.lines.push(cur);
else if (kind === 'Comment') res.comments.push(cur);
}
for (var i = 0; i < lines.length; i++) {
var ln = lines[i];
var s = ln.replace(/^\s+|\s+$/g, '');
if (s.charAt(0) === '[' && s.charAt(s.length - 1) === ']') {
commit(); kind = s.substring(1, s.length - 1); cur = { attrs: [], positions: [] }; continue;
}
if (!cur) continue;
var eq = ln.indexOf('=');
if (eq < 0) continue;
var key = ln.substring(0, eq), val = ln.substring(eq + 1);
if (key === 'Field') {
var toks = _a5erCsv(val);
var pk = toks.length > 4 && _emNorm(toks[4]) !== '';
// ★テスター指摘 No.89: 型トークン (toks[2]) が「*ドメイン名」のときは A5M2 の
// ユーザー定義ドメイン参照。 従来は '*倉庫' のまま格納していたため、 本製品の
// EDM 規約 (型欄のドメイン名を業務データ辞書へ解決) で名前解決が外れていた。
// '*' を剥がしてドメイン名として扱い、 型情報は commit 後に [Manager] の
// DomainInfo から補完する (_a5erResolveDomains — Manager が後方の場合もあるため)。
// 型欄 = 定義域。 '*名前' はユーザー定義ドメイン参照 (型・コメントは commit 後に [Manager] の DomainInfo から補完 —
// _a5erResolveDomains。 Manager が後方の場合もある)、 それ以外はデータ型の直書き (dataType にそのまま)
var _ftyp = _emNorm(toks[2] || '');
var _fuser = '';
if (_ftyp.charAt(0) === '*') _fuser = _ftyp.substring(1).replace(/^\s+/, '');
// ★2026-10-02 (案 A): 属性コメント = Field の 7 番目 (仕様書 4.1.1: "論理名","物理名","型","NOT NULL",キー順,"デフォルト値","コメント",色,
// "オプション" (DDL の列定義の末尾に付く文字列),"追加オプション" (DISABLE))。 従来は $色 の次 (9 番目 = DDL オプション) を読んでいたため、
// A5M2 で書いた属性コメントが設計書の業務的定義に出ず、 変換した .a5er はコメントを 9 番目に書いていた (SETUP の force で作り直される)
var _fcmt = _a5erUnesc(String(toks[6] || ''));
cur.attrs.push({ lname: toks[0] || '', pname: toks[1] || '',
domainName: _fuser, // 定義域名 (ツールのドメイン。 参照でなければ空)
dataType: _fuser ? '' : _ftyp, domainComment: '',
pk: pk, comment: _fcmt,
typeRaw: _ftyp, // ★No.220-9: 表示モード 3 (属性とデータ型) で A5M2 が出す型欄そのもの (*ドメイン / @型 の印つき)
defVal: toks[5] || '', // ★No.229: 既定値 (6 番目)
disabled: String(toks[9] || '').toUpperCase() === 'DISABLE' }); // ★No.221: 無効列 (10 番目の追加オプション)
} else if (key === 'DomainInfo') {
// No.89: [Manager] のユーザー定義ドメイン定義 "名前","型","コメント","既定物理名"
var dtoks = _a5erCsv(val);
var dnm0 = _emNorm(dtoks[0] || '');
if (dnm0) res.domains[dnm0.toLowerCase()] = {
name: dnm0, type: _emNorm(dtoks[1] || ''),
comment: dtoks[2] || '', defCol: _emNorm(dtoks[3] || '') };
} else if (key === 'PageInfo') {
// No.93: ページ定義 "ページ名",表示モード,"用紙サイズ","背景色"
var ptoks = _a5erCsv(val);
var pnm0 = _emNorm(ptoks[0] || '');
if (pnm0) { res.pages.push(pnm0); res.pageMode[pnm0] = parseInt(ptoks[1], 10); res.pageBg[pnm0] = _a5erColorRaw(ptoks[3] || ''); } // No.220-1 / No.220-9
} else if (key === 'Comment') cur.comment = _a5erUnesc(val); // EscapedString (§1.2)
else if (key === 'Query') cur.query = _a5erUnesc(val); // EscapedString (§1.2)
else if (key === 'Position') {
if (kind === 'Relation') {
// ★[Relation] の Position は Entity と形式が異なる (公式仕様 §4.2):
// "ページ名",ラインモード,線位置1,線位置2,線位置3,端子位置1,端子位置2,"頂点リスト"
// 従来は下の Entity 用 regex で誤読し、 ラインモード→x 等のゴミ座標が
// 格納されていた (描画未使用のため実害は無かったが正しくパースする)。
// ・ページ名 = この線を描くページ (複数ページ ER 図での帰属の正)
// ・線位置2 (0-10000) = 中間バー位置。 Bar1-3 は公式仕様で「互換性のための
// 古い項目 (無視してかまいません)」のため、 こちらを優先する
// ★Ver1.0.22 (No.219 / 227、 テスター確認 2026-10-02 = A5M2 同梱の仕様書 4.2.1 と 2.21.1 の実測):
// ラインモード 0 = 自動 / 1 = 縦-横-縦 / 2 = 横-縦-横 / 3 = 縦-横 / 4 = 横-縦 / 5 = ⊐ / 6 = ⊏ / 7 = 直線 (自動) / 8 = 直線 (縦端子) /
// 9 = 直線 (横端子) / 10 = 自由結線。 線位置1 = 親の端子の位置 (辺に沿った 0〜10000)、 線位置2 = 中間バーの位置 (L 字は子の端子)、
// 線位置3 = 子の端子の位置 (既定 5000 = 中央)。 頂点座標リスト (自由結線) = x;y;x;y… (エンティティと同じページ座標、 0.1 mm)。
// ページごとに relPos[ページ] = { mode, p1, p2, p3, verts } に持つ (描画器が経路を作る)
var mr = val.match(/^\s*"([^"]*)",(-?\d+),(-?\d+),(-?\d+),(-?\d+)(?:,([A-Za-z]*),([A-Za-z]*))?(?:,"([^"]*)")?/);
if (mr) {
var rpg = _a5erUnesc(mr[1]), rverts = [], vtoks = String(mr[8] || '').split(';'), vi;
for (vi = 0; vi + 1 < vtoks.length; vi += 2) {
var vx = parseInt(vtoks[vi], 10), vy = parseInt(vtoks[vi + 1], 10);
if (!isNaN(vx) && !isNaN(vy)) rverts.push([vx, vy]);
}
if (!cur.relPages) cur.relPages = [];
cur.relPages.push(rpg);
if (!cur.relPos) cur.relPos = {};
cur.relPos[rpg] = { mode: parseInt(mr[2], 10) || 0, p1: parseInt(mr[3], 10), p2: parseInt(mr[4], 10), p3: parseInt(mr[5], 10), verts: rverts };
if (cur.linePos2 == null) cur.linePos2 = parseInt(mr[4], 10);
}
} else {
// ★テスター指摘 No.66: A5M2 で作成した .a5er は Position="Main",left,top の
// 2 数値のみ (幅・高さ無し) のことがある。 従来は 4 数値必須の regex で
// 取りこぼし、 座標が付かず図が描画されなかった。 2 数値でも left/top を採り、
// 幅・高さの無い Position は先頭 Position のサイズ (それも無ければ描画側の
// 既定値 160/80) を引き継ぐ (pageFilter の Object.create プロトタイプ複製)。
// ★テスター指摘 No.93: Position はページごとに複数持てる (複数ページ ER 図)。
// 全件を positions[] に収集し、 x/y (後方互換の単一座標) は最初の Position を
// 採用する (従来は最後の Position で上書きされていた)。
var m = val.match(/"([^"]*)",(-?\d+),(-?\d+)(?:,(-?\d+),(-?\d+))?/);
if (m) {
var _pos = { page: _a5erUnesc(m[1]), x: +m[2], y: +m[3] };
if (m[4] != null) _pos.w = +m[4];
if (m[5] != null) _pos.h = +m[5];
cur.positions.push(_pos);
if (cur.x == null) {
cur.x = _pos.x; cur.y = _pos.y;
if (_pos.w != null) cur.w = _pos.w;
if (_pos.h != null) cur.h = _pos.h;
}
}
}
} else if (key === 'PName') cur.pname = _emNorm(val);
else if (key === 'LName') cur.lname = _emNorm(val);
else if (key === 'Entity1') cur.e1 = _emNorm(val);
else if (key === 'Entity2') cur.e2 = _emNorm(val);
else if (key === 'Fields1') cur.f1 = _emNorm(val);
else if (key === 'Fields2') cur.f2 = _emNorm(val);
else if (key === 'RelationType1') cur.rt1 = _emNorm(val);
else if (key === 'RelationType2') cur.rt2 = _emNorm(val);
// IDEF1X 表記の描き分けに使う項目 (公式仕様 §4.2 / §4.3 / [Manager])。 IE 表記では未使用
else if (key === 'Dependence') cur.dep = _emNorm(val); // 1=依存 (識別) リレーション
else if (key === 'Cardinarity1') cur.card1 = _emNorm(val); // IDEF1X 表示時のカーディナリティ文字列
else if (key === 'Cardinarity2') cur.card2 = _emNorm(val); // (N個固定のとき数値。 例 "20")
else if (key === 'CompleteCategory') cur.complete = _emNorm(val); // 1=確定カテゴリ (記号の下線 2 本)
else if (key === 'ViewFormat') { if (kind === 'Manager') res.viewFormat = _emNorm(val); }
else if (key === 'UseNondependenceDashLine') { if (kind === 'Manager') res.nonDepDash = _emNorm(val) === '1'; } // ★No.230: IE でも非依存を破線に
else if (key === 'ShowDisableAttributes') { if (kind === 'Manager') res.showDisabled = _emNorm(val) === '1'; } // ★No.221
else if (key === 'Text') { if (kind === 'Shape') cur.text = _a5erUnesc(val); } // ★No.220-2: 図形の中の文字
else if (key === 'FontBold') cur.fontBold = _emNorm(val) === '1'; // ★No.220-7
else if (key === 'FontName') cur.fontName = _emNorm(val); // A5M2 が書いた注記の印 (astah 由来の注記には無い)
else if (key === 'StartLineTermType') cur.startTerm = parseInt(val, 10) || 0; // ★No.220-3: 直線の端 (1 ○ / 2 ● / 3 → / 4 ▶ / 5 ◇ / 6 ◆)
else if (key === 'EndLineTermType') cur.endTerm = parseInt(val, 10) || 0;
else if (key === 'TermPos1') cur.tp1 = _emNorm(val);
else if (key === 'TermPos2') cur.tp2 = _emNorm(val);
else if (key === 'Bar2') cur.bar2 = parseInt(val, 10) || 0;
else if (key === 'SharedMode') cur.shared = _emNorm(val);
else if (key === 'Caption') cur.caption = _emNorm(val); // ★Ver1.0.22 (No.201): リレーションシップ名 / 親→記号の判別属性 (線の横に描く)
else if (key === 'ZOrder') cur.zorder = _emNum(val); // ★Ver1.0.22 (No.199): 注記 / 図形 / 直線の重なり順 (大きいほど手前)
// ★テスター指摘 No.97: エンティティの Tag (種類分け) / Color (前景) / BkColor (背景)
else if (key === 'Tag') cur.tag = _emNorm(val);
else if (key === 'Color') cur.color = _a5erColor(val);
else if (key === 'EffectMode') { if (kind === 'Entity') cur.effectMode = _emNorm(val); } // ★No.246: Gradation = 背景色 → 白の横方向グラデーション
else if (key === 'BkColor') cur.bkColor = (kind === 'Comment') ? _a5erColorRaw(val) : _a5erColor(val); // ★No.220-7: 付箋の白は白 (既定の黄色にしない)
// ★テスター指摘 No.96: [Shape]/[Line]/[Comment] の配置・スタイルキー
else if (key === 'Page') cur.page = _emNorm(val);
// 座標は _emNum で NaN を null に落とす (手編集で値が壊れたファイルでも
// 「NaN が min/max 比較を素通りして viewBox が壊れる」事故を防ぐ)
else if (key === 'Left') cur.left = _emNum(val);
else if (key === 'Top') cur.top = _emNum(val);
else if (key === 'Width') cur.width = _emNum(val);
else if (key === 'Height') cur.height = _emNum(val);
else if (key === 'ShapeType') cur.shapeType = _emNorm(val);
else if (key === 'LineColor') cur.lineColor = (kind === 'Comment') ? _a5erColorRaw(val) : _a5erColor(val); // ★No.220-7: 付箋の枠の黒は黒
else if (key === 'LineType') cur.lineType = parseInt(val, 10) || 0;
else if (key === 'LineWidth') cur.lineWidth = parseInt(val, 10) || 1;
else if (key === 'BrushColor') cur.brushColor = _a5erColor(val);
else if (key === 'BrushAlpha') cur.brushAlpha = parseInt(val, 10);
else if (key === 'FontColor') cur.fontColor = _a5erColor(val);
else if (key === 'FontSize' && (kind === 'Comment' || kind === 'Shape')) cur.fontSize = _emNum(val); // pt (astah 由来の注記 / 図形の文字)
}
commit();
// ドメイン参照 (*名前) の属性に DomainInfo の型・コメントを補完する (定義域の表示用)
for (var di = 0; di < res.entities.length; di++) {
var _de = res.entities[di];
for (var dj = 0; dj < _de.attrs.length; dj++) {
var _da = _de.attrs[dj];
if (!_da.domainName) continue;
var _dd = res.domains[_da.domainName.toLowerCase()];
if (_dd) { _da.dataType = _dd.type; _da.domainComment = String(_dd.comment || ''); }
}
}
return res;
}
// ★Ver1.0.22 (No.220): 白 / 黒も実色として返す版 (付箋の背景色・ページの背景色)。 不正値と $FFFFFFFF は ''
function _a5erColorRaw(v) {
var s = String(v || '').replace(/^\s+|\s+$/g, '');
if (s.charAt(0) !== '$') return '';
var hex = s.substring(1);
if (hex.length === 8) { if (hex.toUpperCase() === 'FFFFFFFF') return ''; hex = hex.substring(2); }
if (!/^[0-9A-Fa-f]{6}$/.test(hex)) return '';
return '#' + hex.substring(4, 6) + hex.substring(2, 4) + hex.substring(0, 2);
}
// A5M2 の Color 値 ($BBGGRR / $AABBGGRR) を CSS の #RRGGBB へ変換。
// $FFFFFFFF (デフォルト色マーカー) と不正値は '' (未指定扱い)。
function _a5erColor(v) {
var s = String(v || '').replace(/^\s+|\s+$/g, '');
if (s.charAt(0) !== '$') return '';
var hex = s.substring(1);
if (hex.length === 8) {
if (hex.toUpperCase() === 'FFFFFFFF') return '';
hex = hex.substring(2); // 上位 2 桁 (アルファ等) を捨て BBGGRR に
}
if (!/^[0-9A-Fa-f]{6}$/.test(hex)) return '';
// 既定色 ($000000=前景既定 / $FFFFFF=背景既定) は「未指定」として扱う。
// A5M2 は色を変えていないエンティティにも既定値の行を書き出すため、 これを実色と
// みなすと既存 EDM の描画 (インディゴ基調) が変わってしまう。 意図的な純黒/純白は
// 製品既定スタイルへ丸められる (許容トレードオフ)。
var hl = hex.toLowerCase();
if (hl === '000000' || hl === 'ffffff') return '';
// $BBGGRR → #RRGGBB
return '#' + hex.substring(4, 6) + hex.substring(2, 4) + hex.substring(0, 2);
}
// ★テスター指摘 No.93: モデルに実在するページ名一覧 (PageInfo 定義順を優先、 未定義は出現順)。
function _a5erContentPages(model) {
var seen = {}, order = [];
function addPage(nm) {
var key = String(nm || '').toLowerCase();
if (!key || seen[key]) return;
seen[key] = true; order.push(nm);
}
function addFromPositions(arr) {
for (var i = 0; i < arr.length; i++) {
var ps = arr[i].positions || [];
for (var j = 0; j < ps.length; j++) addPage(ps[j].page);
}
}
addFromPositions(model.entities);
addFromPositions(model.subtypes);
addFromPositions(model.views || []);
var flat = (model.shapes || []).concat(model.lines || []).concat(model.comments || []);
for (var k = 0; k < flat.length; k++) addPage(flat[k].page);
// PageInfo の定義順を優先し、 未定義ページ (定義漏れ) は出現順で後置
var out = [], used = {};
var decl = model.pages || [];
for (var p = 0; p < decl.length; p++) {
var dk = String(decl[p]).toLowerCase();
if (seen[dk] && !used[dk]) { used[dk] = true; out.push(decl[p]); }
}
for (var q = 0; q < order.length; q++) {
var ok2 = String(order[q]).toLowerCase();
if (!used[ok2]) { used[ok2] = true; out.push(order[q]); }
}
return out;
}
// オブジェクトの指定ページ上の座標 (無ければ null)。 page=null は後方互換 (先頭 Position)。
function _a5erPosOn(o, page) {
if (page == null) return (o.x != null) ? { x: o.x, y: o.y, w: o.w, h: o.h } : null;
var ps = o.positions || [];
for (var i = 0; i < ps.length; i++) {
if (String(ps[i].page || '').toLowerCase() === String(page).toLowerCase()) return ps[i];
}
return null;
}
// 解析済み .a5er モデルを 座標保持の SVG に描画し、 リンクを注入。
// エンティティ名 → EDM.html#edm-ent-<CD> (レジストリ照合) / 属性 → Domains.html#dom-<CD>
// (レジストリ ENTITY_ATTR.DOMAIN_CD)。 戻り: { svg, matchedEntityCds, matchedDomainCds }
// ★テスター指摘 No.93: 複数ページ ER 図に対応。 ページが 2 つ以上あるときは ページごとに
// 描画して縦に積む (各ページに見出し)。 1 ページ以下は従来と同一の出力 (golden 安定)。
function _renderA5erToSvg(model, registry) {
var acc = { matchedEntityCds: {}, matchedDomainCds: {} };
var pages = _a5erContentPages(model);
if (pages.length <= 1) {
var one = _renderA5erPageSvg(model, registry, null, acc, false);
return { svg: one ? one.svg : '', matchedEntityCds: acc.matchedEntityCds, matchedDomainCds: acc.matchedDomainCds };
}
var frags = [], maxW = 0, LABEL_H = 26, GAP = 14;
for (var pi = 0; pi < pages.length; pi++) {
var fr = _renderA5erPageSvg(model, registry, pages[pi], acc, true);
if (!fr) continue;
frags.push({ name: pages[pi], f: fr });
if (fr.W > maxW) maxW = fr.W;
}
if (!frags.length) return { svg: '', matchedEntityCds: acc.matchedEntityCds, matchedDomainCds: acc.matchedDomainCds };
var body = '', totH = 0, pageSvgs = [];
var OPEN = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ';
for (var fi = 0; fi < frags.length; fi++) {
var fg = frags[fi];
// ★ページ単位の <g> (data-page / 位置・寸法): EDM プレビューのビューアがページ切替に使う (2026-09-19)
body += '<g class="tfc-a5er-page" data-page="' + _erEscAttr(fg.name) + '" data-y="' + totH + '" data-w="' + fg.f.W +
'" data-h="' + (LABEL_H + fg.f.H) + '">';
body += '<text x="6" y="' + (totH + 17) + '" font-size="13" font-weight="bold" fill="#334155">' +
_erEsc('▤ ' + fg.name) + '</text>';
body += '<svg y="' + (totH + LABEL_H) + '" width="' + fg.f.W + '" height="' + fg.f.H +
'" viewBox="0 0 ' + fg.f.W + ' ' + fg.f.H + '">' + fg.f.inner + '</svg>';
body += '</g>';
totH += LABEL_H + fg.f.H + GAP;
// ★設計書 EDM.html のページ別タブ用: ページ単体の SVG (単一ページ描画と同じ形)
pageSvgs.push({ name: fg.name, W: fg.f.W, H: fg.f.H,
svg: OPEN + fg.f.W + ' ' + fg.f.H + '" font-family="\'Yu Gothic UI\',\'Meiryo\',sans-serif">' + fg.f.inner + '</svg>' });
}
var svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + Math.max(maxW, 200) + ' ' + totH +
'" font-family="\'Yu Gothic UI\',\'Meiryo\',sans-serif">' +
'<rect class="tfc-a5er-bg" width="' + Math.max(maxW, 200) + '" height="' + totH + '" fill="#f8fafc"/>' + body + '</svg>';
return { svg: svg, pages: pageSvgs, matchedEntityCds: acc.matchedEntityCds, matchedDomainCds: acc.matchedDomainCds };
}
// 1 ページ分の描画。 page=null は後方互換 (単一ページ、 従来と同一出力)。
// embed=true: 入れ子 <svg> 用に svg タグを付けず inner を返す。
// 戻り: { svg, inner, W, H } または null (描画対象なし)
function _renderA5erPageSvg(model, registry, page, acc, embed) {
var matchedEntityCds = acc.matchedEntityCds, matchedDomainCds = acc.matchedDomainCds;
// ページ上のオブジェクトへ絞り込み (page=null は全件 = 従来挙動)。
// Object.create のプロトタイプ複製で座標だけ差し替える (attrs 等は共有)。
function pageFilter(arr) {
if (page == null) return arr;
var out = [];
for (var i = 0; i < arr.length; i++) {
var p = _a5erPosOn(arr[i], page);
if (!p) continue;
var c = Object.create(arr[i]);
c.x = p.x; c.y = p.y;
if (p.w != null) c.w = p.w;
if (p.h != null) c.h = p.h;
out.push(c);
}
return out;
}
function pageFlat(arr) {
if (page == null) return arr || [];
var out = [];
for (var i = 0; i < (arr || []).length; i++) {
if (String(arr[i].page || '').toLowerCase() === String(page).toLowerCase()) out.push(arr[i]);
}
return out;
}
var ents = pageFilter(model.entities);
var psubs = pageFilter(model.subtypes);
var pviews = pageFilter(model.views || []);
var pshapes = pageFlat(model.shapes);
var plines = pageFlat(model.lines);
var pcomments = pageFlat(model.comments);
if (!ents.length && !pviews.length && !pcomments.length) return null;
var hasReg = registry && registry.hasData;
var minx = 1e9, miny = 1e9, maxx = -1e9, maxy = -1e9, any = false;
for (var i = 0; i < ents.length; i++) {
var e = ents[i]; if (e.x == null) continue; any = true;
var w = e.w || 160, h = e.h || 80;
if (e.x < minx) minx = e.x; if (e.y < miny) miny = e.y;
if (e.x + w > maxx) maxx = e.x + w; if (e.y + h > maxy) maxy = e.y + h;
}
// ★No.96: View / Shape / Line / Comment もバウンドに含める (見切れ防止。 無ければ従来同一)
for (var vb = 0; vb < pviews.length; vb++) {
var vv = pviews[vb]; if (vv.x == null) continue; any = true;
var vw0 = vv.w || 160, vh0 = vv.h || 80;
if (vv.x < minx) minx = vv.x; if (vv.y < miny) miny = vv.y;
if (vv.x + vw0 > maxx) maxx = vv.x + vw0; if (vv.y + vh0 > maxy) maxy = vv.y + vh0;
}
var flatB = pshapes.concat(plines).concat(pcomments);
for (var fb = 0; fb < flatB.length; fb++) {
var fo = flatB[fb];
if (fo.left == null || fo.top == null) continue;
any = true;
var fx0 = Math.min(fo.left, fo.left + (fo.width || 0));
var fy0 = Math.min(fo.top, fo.top + (fo.height || 0));
var fx1 = Math.max(fo.left, fo.left + (fo.width || 0));
var fy1 = Math.max(fo.top, fo.top + (fo.height || 0));
if (fx0 < minx) minx = fx0; if (fy0 < miny) miny = fy0;
if (fx1 > maxx) maxx = fx1; if (fy1 > maxy) maxy = fy1;
}
if (!any) return null;
// ★No.256: リレーションシップの経路の頂点 (自由結線 10) と ⊐ / ⊏ (5 / 6) のバーもバウンドに含める (エンティティの外を回る線の見切れ防止。 無ければ従来同一)。
// relPosOn は後ろの関数宣言 (同じ関数の直下 = 巻き上げ)。 大きさ自動の箱は既定の 160 × 80 で見積もる (バーは箱の外側 40 mm × 線位置2 なので十分)
var entByP = {}, eb;
for (eb = 0; eb < ents.length; eb++) if (ents[eb].x != null) entByP[ents[eb].pname] = ents[eb];
for (var rb = 0; rb < model.relations.length; rb++) {
var relB = model.relations[rb], rpB = relPosOn(relB, page); if (!rpB) continue;
if (rpB.mode === 10 && rpB.verts && rpB.verts.length) {
for (var rv = 0; rv < rpB.verts.length; rv++) {
var vx0 = rpB.verts[rv][0], vy0 = rpB.verts[rv][1];
if (vx0 < minx) minx = vx0; if (vy0 < miny) miny = vy0; if (vx0 > maxx) maxx = vx0; if (vy0 > maxy) maxy = vy0;
}
} else if (rpB.mode === 5 || rpB.mode === 6) {
var gb1 = entByP[relB.e1], gb2 = entByP[relB.e2]; if (!gb1 || !gb2) continue;
var fb2 = (rpB.p2 != null && rpB.p2 >= 0 && rpB.p2 <= 10000) ? rpB.p2 / 10000 : 0.5, extB = 400 * (fb2 / 0.5);
var barB = rpB.mode === 5 ? Math.max(gb1.x + (gb1.w || 160), gb2.x + (gb2.w || 160)) + extB : Math.min(gb1.x, gb2.x) - extB;
if (barB < minx) minx = barB; if (barB > maxx) maxx = barB;
}
}
var pad = 40; minx -= pad; miny -= pad; maxx += pad; maxy += pad;
var W = Math.round(maxx - minx), H = Math.round(maxy - miny);
function X(v) { return Math.round(v - minx); }
function Y(v) { return Math.round(v - miny); }
function card(lname) { return hasReg ? (registry.byName[_emNorm(lname)] || null) : null; }
// FK 集合: リレーション (サブタイプ以外) の子側フィールド (Entity2.Fields2) を FK とみなす。
// 複合キーは Fields2 がカンマ区切りになるため、 列ごとに分割して登録する
// (No.7: 複数列リレーションで子側の (FK) が 1 つも表示されなかった)
// IDEF1X 表記 ([Manager] ViewFormat=1): A5M2 の IDEF1X 表示に合わせて描き分ける (非依存は破線、 端記号)。
// 依存リレーション (Dependence=1) の子 = 従属エンティティ (角丸の箱)。 ★Ver1.0.22 (No.200): 角丸は IE 表記でも同じ (A5M2 は表記に関わらず角丸)
var idef = String(model.viewFormat || '0') === '1';
var nonDepDash = !!model.nonDepDash; // ★No.230: IE でも非依存を破線 (A5M2 の UseNondependenceDashLine=1)
var _pm0 = model.pageMode || {}, _pgKey = page != null ? page : (model.pages || [])[0];
var showTypes = _pm0[_pgKey] === 3; // ★No.220-9: PageInfo の表示モード 3 = 属性とデータ型
var showDisabled = !!model.showDisabled;
// ★No.221: 無効列 (DISABLE) は A5M2 の既定 (ShowDisableAttributes=0) どおり描かない
function visibleAttrs(e) { var out = [], k; for (k = 0; k < e.attrs.length; k++) if (showDisabled || !e.attrs[k].disabled) out.push(e.attrs[k]); return out; }
function textW(str, fs) { var w = 0, k; str = String(str || ''); for (k = 0; k < str.length; k++) w += (str.charCodeAt(k) > 0x2E7F) ? fs : fs * 0.58; return w; }
// ★No.216: A5M2 の「大きさ自動」(Position に幅・高さが無い) は属性の行数と文字幅から箱の大きさを決める
function autoSize(e, vis) {
var w = e.w, h = e.h, k;
if (!h) h = 22 + 16 * Math.max(1, vis.length) + 6;
if (!w) {
var mw = textW(e.lname || e.pname || '', 11.5) + 24;
for (k = 0; k < vis.length; k++) mw = Math.max(mw, textW(vis[k].lname + (showTypes && vis[k].typeRaw ? ' ' + vis[k].typeRaw : '') + ' (FK)', 10.5) + 16);
w = Math.max(120, Math.round(mw));
}
return { w: w, h: h };
}
var depSet = {};
var fkSet = {};
for (var fri = 0; fri < model.relations.length; fri++) {
var fr = model.relations[fri];
if (fr.dep === '1' && fr.e2) depSet[fr.e2] = true;
if (!fr.e2 || !fr.f2) continue;
var f2cols = String(fr.f2).split(',');
for (var fci = 0; fci < f2cols.length; fci++) {
var fcol = f2cols[fci].replace(/^\s+|\s+$/g, '');
if (fcol) fkSet[fr.e2 + '|' + fcol] = true;
}
}
// ジオメトリ事前計算: エンティティ(属性行Y込・PK優先並べ替え) + サブタイプノード
var geom = {};
for (var gi = 0; gi < ents.length; gi++) {
var ge = ents[gi]; if (ge.x == null) continue;
var gvis = visibleAttrs(ge), gauto = autoSize(ge, gvis);
var gx = X(ge.x), gy = Y(ge.y), gw = gauto.w, gh = gauto.h;
var gna = gvis.length || 1;
var grow = Math.max(13, Math.min(18, (gh - 26) / gna));
// PK を上段へ並べ替え (PK→非PK、 各々は元順序維持)
var pks = [], nons = [];
for (var gk = 0; gk < gvis.length; gk++) { (gvis[gk].pk ? pks : nons).push(gvis[gk]); }
var ordered = pks.concat(nons);
var attrY = {};
for (var oi = 0; oi < ordered.length; oi++) attrY[ordered[oi].pname] = gy + 22 + grow * (oi + 0.5);
geom[ge.pname] = { x: gx, y: gy, w: gw, h: gh, rowH: grow, attrY: attrY, isSub: false,
ordered: ordered, pkCount: pks.length, pname: ge.pname };
}
for (var si = 0; si < psubs.length; si++) {
var st = psubs[si]; if (st.x == null) continue;
geom[st.pname] = { x: X(st.x), y: Y(st.y), w: st.w || 60, h: st.h || 44, isSub: true, shared: st.shared };
}
var s = embed ? '' : ('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + W + ' ' + H +
'" font-family="\'Yu Gothic UI\',\'Meiryo\',sans-serif">');
s += '<rect width="' + W + '" height="' + H + '" fill="' + ((model.pageBg && _pgKey != null && model.pageBg[_pgKey]) || '#ffffff') + '"/>'; // ★No.220-1: PageInfo の背景色
// ★テスター指摘 No.96: [Shape] / [Line] を背面 (リレーション・エンティティより奥) に描画
// ★Ver1.0.22 (No.199): ZOrder を持つ注記 (他ツールから変換したもの) は図形・直線と同じ層で ZOrder 順 (小さい = 奥) に重ねる
// (astah で矩形の後ろに隠れているテキストは A5M2 でも隠れる)。 ZOrder の無い注記は従来どおり最前面の付箋 (下)
var backAnn = [], frontComments = [], bi;
for (bi = 0; bi < pshapes.length; bi++) backAnn.push({ k: 0, z: pshapes[bi].zorder, o: pshapes[bi], i: bi });
for (bi = 0; bi < plines.length; bi++) backAnn.push({ k: 1, z: plines[bi].zorder, o: plines[bi], i: bi });
for (bi = 0; bi < pcomments.length; bi++) {
if (pcomments[bi].zorder != null) backAnn.push({ k: 2, z: pcomments[bi].zorder, o: pcomments[bi], i: bi });
else frontComments.push(pcomments[bi]);
}
backAnn.sort(function (a, b) { // ZOrder 無し (= 奥) → ZOrder 昇順。 同順は 図形 → 直線 → 注記、 出現順
var za = (a.z == null) ? -Infinity : a.z, zb = (b.z == null) ? -Infinity : b.z;
if (za !== zb) return za < zb ? -1 : 1;
if (a.k !== b.k) return a.k - b.k;
return a.i - b.i;
});
for (bi = 0; bi < backAnn.length; bi++) {
if (backAnn[bi].k === 0) s += _a5erShapeSvg(backAnn[bi].o, X, Y) + _a5erShapeTextSvg(backAnn[bi].o, X, Y); // ★No.220-2: 図形の中の文字
else if (backAnn[bi].k === 1) s += _a5erLineSvg(backAnn[bi].o, X, Y);
else s += _a5erCommentSvg(backAnn[bi].o, X, Y);
}
// リレーション線 (フィールド行に接続 + カーディナリティ記号)。
// A5M2 RelationType (公式 a5er_specification.md):
// 0=指定なし(バー) / 1=0または1(○+バー) / 2=1(バー) / 3=0以上(○+鳥の足) /
// 4=1以上(バー+鳥の足) / 5=N個固定(鳥の足)
// ※テスター指摘 No.49 対応時に公式仕様と照合し、 旧実装の 1↔2 取り違え
// (○ を 2/4 に描いていた) を是正。
// 同一エンティティ間の複数関連 (例: 倉庫→製造指示 の完成入庫/材料出庫) は
// 接続する属性行が異なるため Y がずれ、 2 本に分離される。
function marker(px, py, ox, oy, rt, card) {
var qx = -oy, qy = ox;
if (rt === '0') return ''; // ★No.217: 指定なし = 端記号を描かない (A5M2 と同じ)
var g = '', many = (rt === '3' || rt === '4' || rt === '5'), zero = (rt === '1' || rt === '3');
if (rt === '5' && card) { // ★No.223: 定数 (N 個固定) は個数を端の脇に
g += '<text x="' + (px + ox * 22 + qx * 9) + '" y="' + (py + oy * 22 + qy * 9 + 3.5) + '" font-size="9.5" fill="#475569" text-anchor="middle">' + _erEsc(card) + '</text>';
}
if (many) {
var ax = px + ox * 14, ay = py + oy * 14;
g += '<line x1="' + ax + '" y1="' + ay + '" x2="' + px + '" y2="' + py + '" stroke="#64748b" stroke-width="1.1"/>';
g += '<line x1="' + ax + '" y1="' + ay + '" x2="' + (px + qx * 6) + '" y2="' + (py + qy * 6) + '" stroke="#64748b" stroke-width="1.1"/>';
g += '<line x1="' + ax + '" y1="' + ay + '" x2="' + (px - qx * 6) + '" y2="' + (py - qy * 6) + '" stroke="#64748b" stroke-width="1.1"/>';
if (rt === '4') {
// 1以上 = 鳥の足 + バー
var b4x = px + ox * 19, b4y = py + oy * 19;
g += '<line x1="' + (b4x + qx * 5) + '" y1="' + (b4y + qy * 5) + '" x2="' + (b4x - qx * 5) + '" y2="' + (b4y - qy * 5) + '" stroke="#64748b" stroke-width="1.3"/>';
}
} else {
var bx = px + ox * 9, by = py + oy * 9;
g += '<line x1="' + (bx + qx * 5) + '" y1="' + (by + qy * 5) + '" x2="' + (bx - qx * 5) + '" y2="' + (by - qy * 5) + '" stroke="#64748b" stroke-width="1.3"/>';
}
if (zero) g += '<circle cx="' + (px + ox * 19) + '" cy="' + (py + oy * 19) + '" r="3.5" fill="#ffffff" stroke="#64748b" stroke-width="1.1"/>';
return g;
}
// IDEF1X 表記の端記号 (A5M2 の IDEF1X 表示を実測して合わせた):
// 子側 (Entity2) = ● (箱の辺に接する)。 カーディナリティは ● の脇に文字
// RelationType2: 1 (0または1)=Z / 4 (1以上)=P / 2 (1)=1 / 5 (N個固定)=Cardinarity2 の値 / 0・3 (0以上)=無し
// 親側 (Entity1) = RelationType1=1 (0または1 = 任意の親) のとき ◇、 それ以外 (=1 等) は記号無し
function markerIdef(px, py, ox, oy, rt, card, isChild) {
var qx = -oy, qy = ox, g = '';
if (isChild) {
g += '<circle cx="' + (px + ox * 4) + '" cy="' + (py + oy * 4) + '" r="4" fill="#64748b"/>';
var letter = (rt === '1') ? 'Z' : (rt === '4') ? 'P' : (rt === '2') ? '1' : (rt === '5') ? (card || 'n') : '';
if (letter) {
g += '<text x="' + (px + ox * 13 + qx * 9) + '" y="' + (py + oy * 13 + qy * 9 + 3.5) +
'" font-size="9.5" fill="#475569" text-anchor="middle">' + _erEsc(letter) + '</text>';
}
} else if (rt === '3' || rt === '4' || rt === '5') {
// ★No.180: 親側も「多」(多対多の関連 = 0以上 / 1以上) なら子側と同じ ● + 文字 (A5M2 の IDEF1X 表示と同じ)
g += '<circle cx="' + (px + ox * 4) + '" cy="' + (py + oy * 4) + '" r="4" fill="#64748b"/>';
var pl = (rt === '4') ? 'P' : (rt === '5') ? (card || 'n') : '';
if (pl) {
g += '<text x="' + (px + ox * 13 + qx * 9) + '" y="' + (py + oy * 13 + qy * 9 + 3.5) +
'" font-size="9.5" fill="#475569" text-anchor="middle">' + _erEsc(pl) + '</text>';
}
} else if (rt === '1') {
var dx = px + ox * 7, dy = py + oy * 7;
g += '<polygon points="' + (dx + ox * 7) + ',' + (dy + oy * 7) + ' ' + (dx + qx * 4.5) + ',' + (dy + qy * 4.5) + ' ' +
(dx - ox * 7) + ',' + (dy - oy * 7) + ' ' + (dx - qx * 4.5) + ',' + (dy - qy * 4.5) +
'" fill="#ffffff" stroke="#64748b" stroke-width="1.1"/>';
}
return g;
}
// エンティティ端の接続点 (相手の方向に面した辺に接続)。
// side: A5M2 の TermPos ('R'/'L') を尊重 (No.8: 利用者が箱を避けて引いた線の再現)。
// 左右のみ扱う (A5M2 の TermPos は左右端子の指定)。
// 自動時 (side 無し): 相手エンティティとの位置関係で 左右辺 or 上下辺を選ぶ。
// ★縦積み対応: X レンジが重なり Y が離れている相手 (真上/真下の箱) は 上下辺に接続する。
// 左右辺固定だと 中心がわずかにずれるだけで両端が逆の外側へ出て、 カーディナリティ
// 記号 (ー/○) が相手と反対側にはみ出す不具合になる (縦積みサブタイプで顕著)。
// 戻り: {x, y, ox, oy} ox/oy = 外向き単位ベクトル (左右辺: ox=±1,oy=0 / 上下辺: ox=0,oy=±1)
function endpoint(g, fieldPn, other, side) {
var cx = g.x + g.w / 2, cy = g.y + g.h / 2;
if (g.isSub) return { x: cx, y: cy, ox: 0, oy: 0 }; // サブタイプノードは中心接続
function edgeLR(right) {
var ey = (fieldPn && g.attrY && g.attrY[fieldPn] != null) ? g.attrY[fieldPn] : cy;
return right ? { x: g.x + g.w, y: ey, ox: 1, oy: 0 } : { x: g.x, y: ey, ox: -1, oy: 0 };
}
if (side === 'R') return edgeLR(true);
if (side === 'L') return edgeLR(false);
var ocx = other.x + other.w / 2, ocy = other.y + other.h / 2;
// X レンジが重なる かつ Y レンジが重ならない = 真上/真下の箱 → 上下辺で接続
var xOverlap = (g.x < other.x + other.w) && (other.x < g.x + g.w);
var yOverlap = (g.y < other.y + other.h) && (other.y < g.y + g.h);
if (xOverlap && !yOverlap) {
// 接続 X は 両箱の重なり X 区間の中央 (縦線が両箱に収まる)
var ox0 = Math.max(g.x, other.x), ox1 = Math.min(g.x + g.w, other.x + other.w);
var jx = (ox0 + ox1) / 2;
return (ocy >= cy) ? { x: jx, y: g.y + g.h, ox: 0, oy: 1 } : { x: jx, y: g.y, ox: 0, oy: -1 };
}
return edgeLR(ocx >= cx);
}
// 複合キー (カンマ区切り Fields) は先頭列の行に線を接続する
function firstField(fs) {
return fs ? String(fs).split(',')[0].replace(/^\s+|\s+$/g, '') : fs;
}
// ★Ver1.0.22 (No.201): 折れ線の中点 (全長の半分) の横に文字を置く。 水平な区間なら上に、 垂直な区間なら右に
function routeCaption(route, text) {
var pts = [], toks = String(route).split(' ');
for (var ti = 0; ti < toks.length; ti++) { var xy = toks[ti].split(','); if (xy.length === 2) pts.push([parseFloat(xy[0]), parseFloat(xy[1])]); }
if (pts.length < 2) return '';
var total = 0, segs = [];
for (var si = 1; si < pts.length; si++) { var dl = Math.abs(pts[si][0] - pts[si - 1][0]) + Math.abs(pts[si][1] - pts[si - 1][1]); segs.push(dl); total += dl; }
var half = total / 2, acc = 0, cx = pts[0][0], cy = pts[0][1], horiz = true;
for (var sj = 0; sj < segs.length; sj++) {
if (acc + segs[sj] >= half || sj === segs.length - 1) {
var t = segs[sj] > 0 ? (half - acc) / segs[sj] : 0;
cx = pts[sj][0] + (pts[sj + 1][0] - pts[sj][0]) * t; cy = pts[sj][1] + (pts[sj + 1][1] - pts[sj][1]) * t;
horiz = Math.abs(pts[sj + 1][1] - pts[sj][1]) < 0.5;
break;
}
acc += segs[sj];
}
// ★No.252: A5M2 はリレーションシップ名を白い背景の枠付きで線の上に描く (線が文字を横切らない)。 幅は文字数の概算 (9 px / 字 + 余白)
var tw = Math.round(String(text).length * 9) + 8, th = 13;
return '<rect class="tfc-rel-cap" x="' + Math.round(cx - tw / 2) + '" y="' + Math.round(cy - th / 2) + '" width="' + tw + '" height="' + th + '" fill="#ffffff" stroke="#cbd5e1" stroke-width="0.8"/>' +
'<text x="' + Math.round(cx) + '" y="' + Math.round(cy + 3.5) + '" font-size="9.5" fill="#475569" text-anchor="middle">' + _erEsc(text) + '</text>';
}
// 直交ルート文字列を生成 (端子の外向き方向 ox/oy に応じて L 字/Z 字/C 字)。
// frac = A5M2 Bar2 (‰) に基づく中間バー位置 (利用者の手動調整を再現)
function orthoRoute(e1, e2, frac) {
var v1 = (e1.oy !== 0), v2 = (e2.oy !== 0);
if (!v1 && !v2) {
// 両端 左右辺
if (e1.ox === e2.ox) {
// 同一辺 (C 字): 外側にバーを立てる
var ext = 24;
var bx = e1.ox > 0 ? Math.max(e1.x, e2.x) + ext : Math.min(e1.x, e2.x) - ext;
return e1.x + ',' + e1.y + ' ' + bx + ',' + e1.y + ' ' + bx + ',' + e2.y + ' ' + e2.x + ',' + e2.y;
}
// 対向 (Z 字): 中間縦バー
var mx = e1.x + (e2.x - e1.x) * frac;
return e1.x + ',' + e1.y + ' ' + mx + ',' + e1.y + ' ' + mx + ',' + e2.y + ' ' + e2.x + ',' + e2.y;
}
if (v1 && v2) {
// 両端 上下辺
if (e1.oy === e2.oy) {
var exty = 24;
var by = e1.oy > 0 ? Math.max(e1.y, e2.y) + exty : Math.min(e1.y, e2.y) - exty;
return e1.x + ',' + e1.y + ' ' + e1.x + ',' + by + ' ' + e2.x + ',' + by + ' ' + e2.x + ',' + e2.y;
}
// 対向 (Z 字・縦): 中間横バー
var my = e1.y + (e2.y - e1.y) * frac;
return e1.x + ',' + e1.y + ' ' + e1.x + ',' + my + ' ' + e2.x + ',' + my + ' ' + e2.x + ',' + e2.y;
}
// 片方 左右辺・片方 上下辺 (L 字): 縦辺側の X と横辺側の Y で角を作る
var vert = v1 ? e1 : e2, horiz = v1 ? e2 : e1;
var cxp = vert.x, cyp = horiz.y;
if (v1) return e1.x + ',' + e1.y + ' ' + cxp + ',' + cyp + ' ' + e2.x + ',' + e2.y;
return e1.x + ',' + e1.y + ' ' + cxp + ',' + cyp + ' ' + e2.x + ',' + e2.y;
}
// ★Ver1.0.22 (No.219 / 227): A5M2 の線の経路を再現する (テスター実測 2026-10-02、 親 1 つと 12 方向の子 / ラインモード 1〜10)。
// 端子 = 辺に沿った位置 (線位置1 = 親、 線位置3 = 子。 既定 5000 = 辺の中央)、 Z 字の中間バー = 線位置2 (辺と辺の間の比率)。
// 自動 (0) の向き = 箱が上下に重なる → 縦、 左右に重なる → 横、 どちらも重ならない (斜め) → 中心の差が |dy| ≥ |dx| なら 縦-横-縦、 それ以外は 横-縦-横
// (±900/±900 の斜めは 縦-横-縦、 上やや左 / 下やや右は縦、 左やや上 / 右やや下は横)。 L 字 (3 / 4) の子の端子は線位置2、
// ⊐ / ⊏ (5 / 6) は両端とも右辺 (左辺) でバーは箱の外側 40 mm × 線位置2/5000、 直線 (7 / 8 / 9) は端子を結ぶだけ、 自由結線 (10) は頂点をそのまま
// (端子は頂点の方向の辺)。 単位: 1 = 0.1 mm = 1 px
function term(g, side, f) {
if (f == null || isNaN(f) || f < 0 || f > 1) f = 0.5;
if (side === 'T') return { x: g.x + g.w * f, y: g.y, ox: 0, oy: -1 };
if (side === 'B') return { x: g.x + g.w * f, y: g.y + g.h, ox: 0, oy: 1 };
if (side === 'L') return { x: g.x, y: g.y + g.h * f, ox: -1, oy: 0 };
return { x: g.x + g.w, y: g.y + g.h * f, ox: 1, oy: 0 };
}
function orient(g1, g2) { // 'V' 縦 / 'H' 横 / 'O' 箱が重なる
var xOv = (g1.x < g2.x + g2.w) && (g2.x < g1.x + g1.w), yOv = (g1.y < g2.y + g2.h) && (g2.y < g1.y + g1.h);
if (xOv && !yOv) return 'V';
if (yOv && !xOv) return 'H';
if (xOv && yOv) return 'O';
var dx = (g2.x + g2.w / 2) - (g1.x + g1.w / 2), dy = (g2.y + g2.h / 2) - (g1.y + g1.h / 2);
return Math.abs(dy) >= Math.abs(dx) ? 'V' : 'H';
}
function vSides(g1, g2) { return (g2.y + g2.h / 2 >= g1.y + g1.h / 2) ? ['B', 'T'] : ['T', 'B']; }
function hSides(g1, g2) { return (g2.x + g2.w / 2 >= g1.x + g1.w / 2) ? ['R', 'L'] : ['L', 'R']; }
function sideToward(g, px, py) {
var dx = px - (g.x + g.w / 2), dy = py - (g.y + g.h / 2);
if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? 'R' : 'L';
return dy >= 0 ? 'B' : 'T';
}
function ptsStr(arr) { var o = [], k; for (k = 0; k < arr.length; k++) o.push(Math.round(arr[k][0]) + ',' + Math.round(arr[k][1])); return o.join(' '); }
function relPosOn(rel, pg) {
if (!rel.relPos) return null;
if (pg == null) { for (var k0 in rel.relPos) if (rel.relPos.hasOwnProperty(k0)) return rel.relPos[k0]; return null; }
var lp = String(pg).toLowerCase();
for (var k1 in rel.relPos) if (rel.relPos.hasOwnProperty(k1) && String(k1).toLowerCase() === lp) return rel.relPos[k1];
return null;
}
function relRoute(rel, g1, g2, rp) {
var mode = rp ? (rp.mode || 0) : 0, f1 = rp && rp.p1 != null ? rp.p1 / 10000 : 0.5, f2 = rp && rp.p2 != null ? rp.p2 / 10000 : 0.5, f3 = rp && rp.p3 != null ? rp.p3 / 10000 : 0.5;
if (!(f2 >= 0 && f2 <= 1)) f2 = 0.5;
var o = orient(g1, g2), sd, e1, e2, bar, k;
if (mode === 10 && rp.verts && rp.verts.length) {
var vs = [];
for (k = 0; k < rp.verts.length; k++) vs.push([X(rp.verts[k][0]), Y(rp.verts[k][1])]);
e1 = term(g1, sideToward(g1, vs[0][0], vs[0][1]), f1);
e2 = term(g2, sideToward(g2, vs[vs.length - 1][0], vs[vs.length - 1][1]), f3);
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y]].concat(vs).concat([[e2.x, e2.y]])) };
}
if (g1 === g2) { // ★No.258: 自己参照は右辺の 20% から出て 40% に戻る 40 px の C 字 (既定の線位置 (中央) のままだと出入りが同じ点に重なって記号しか見えず、 他の線に埋もれる。
// 上寄りにして中央 (50%) に付く他の線と重ねない)
var fs1 = (rp && rp.p1 != null && rp.p1 !== 5000 && f1 >= 0 && f1 <= 1) ? f1 : 0.2, fs3 = (rp && rp.p3 != null && rp.p3 !== 5000 && f3 >= 0 && f3 <= 1) ? f3 : 0.4;
e1 = term(g1, 'R', fs1); e2 = term(g1, 'R', fs3);
bar = Math.max(e1.x, e2.x) + 40;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [bar, e1.y], [bar, e2.y], [e2.x, e2.y]]) };
}
if (mode === 7 || mode === 8 || mode === 9) {
var so = mode === 8 ? 'V' : mode === 9 ? 'H' : (o === 'O' ? 'H' : o);
sd = so === 'V' ? vSides(g1, g2) : hSides(g1, g2);
e1 = term(g1, sd[0], f1); e2 = term(g2, sd[1], f3);
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [e2.x, e2.y]]) };
}
if (mode === 3 || mode === 4) {
var pv = mode === 3;
sd = [pv ? vSides(g1, g2)[0] : hSides(g1, g2)[0], pv ? hSides(g1, g2)[1] : vSides(g1, g2)[1]];
e1 = term(g1, sd[0], f1); e2 = term(g2, sd[1], f2);
return { e1: e1, e2: e2, route: ptsStr(pv ? [[e1.x, e1.y], [e1.x, e2.y], [e2.x, e2.y]] : [[e1.x, e1.y], [e2.x, e1.y], [e2.x, e2.y]]) };
}
if (mode === 5 || mode === 6) {
var right = mode === 5, ext = 400 * (f2 / 0.5);
e1 = term(g1, right ? 'R' : 'L', f1); e2 = term(g2, right ? 'R' : 'L', f3);
bar = right ? Math.max(g1.x + g1.w, g2.x + g2.w) + ext : Math.min(g1.x, g2.x) - ext;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [bar, e1.y], [bar, e2.y], [e2.x, e2.y]]) };
}
if (mode !== 1 && mode !== 2 && o === 'O') { // 箱が重なる: 左右辺 (同じ辺なら外側に C 字)
var c1 = g1.x + g1.w / 2, c2 = g2.x + g2.w / 2;
e1 = term(g1, c2 >= c1 ? 'R' : 'L', f1); e2 = term(g2, c1 >= c2 ? 'R' : 'L', f3);
if (e1.ox === e2.ox) {
bar = e1.ox > 0 ? Math.max(e1.x, e2.x) + 24 : Math.min(e1.x, e2.x) - 24;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [bar, e1.y], [bar, e2.y], [e2.x, e2.y]]) };
}
bar = e1.x + (e2.x - e1.x) * f2;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [bar, e1.y], [bar, e2.y], [e2.x, e2.y]]) };
}
var vert = mode === 1 ? true : mode === 2 ? false : (o === 'V');
if (vert) {
sd = vSides(g1, g2); e1 = term(g1, sd[0], f1); e2 = term(g2, sd[1], f3);
bar = e1.y + (e2.y - e1.y) * f2;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [e1.x, bar], [e2.x, bar], [e2.x, e2.y]]) };
}
sd = hSides(g1, g2); e1 = term(g1, sd[0], f1); e2 = term(g2, sd[1], f3);
bar = e1.x + (e2.x - e1.x) * f2;
return { e1: e1, e2: e2, route: ptsStr([[e1.x, e1.y], [bar, e1.y], [bar, e2.y], [e2.x, e2.y]]) };
}
// 通常リレーション (サブタイプノードに繋がるものは後段でツリー描画するため除外)
for (var ri = 0; ri < model.relations.length; ri++) {
var rel = model.relations[ri], g1 = geom[rel.e1], g2 = geom[rel.e2];
if (!g1 || !g2) continue;
if (g1.isSub || g2.isSub) continue;
// ★複数ページ: Relation 自身の Position ページ (= この線を描くページの正) を尊重。
// Position の無い古い/簡易ファイルは従来どおり「両端エンティティが居るページ」に描く。
if (page != null && rel.relPages && rel.relPages.length) {
var _rpOk = false, _rpl = String(page).toLowerCase();
for (var _rp = 0; _rp < rel.relPages.length; _rp++) {
if (String(rel.relPages[_rp]).toLowerCase() === _rpl) { _rpOk = true; break; }
}
if (!_rpOk) continue;
}
// A5:SQL Mk-2 の TermPos1/2 (端子の辺) は 端子側の指定には使わない。
// ・既定シリアライズが R/R (自動配線) で幾何情報を持たない (生産管理モデルは全て R/R)。
// ・非対称値 (例: tp1=L/tp2=R) を字義どおり尊重すると、 相手が反対側にある箱で
// 両端が相手と逆の外側へ出て、 線が箱を回り込みカーディナリティ記号 (ー/○) が
// 相手と反対側にはみ出す (拠点⇔要員 で顕在化)。
// → 端子側は常に「相手エンティティに面した辺」を選ぶ幾何学的自動配線とする
// (endpoint 内で 左右/上下 を相対位置から決定)。 A5M2 が既定 (R/R) で表示する
// 配線と一致する。 中間バー位置のみ Bar2 (‰) を尊重する (No.8 の主眼)。
// ★No.219 / 227: 経路 = Position のラインモード・線位置・頂点 (relRoute)。 端子は辺の上の線位置 (既定 = 中央 = A5M2 の表示)
var rr0 = relRoute(rel, g1, g2, relPosOn(rel, page)), e1 = rr0.e1, e2 = rr0.e2, route = rr0.route;
var rstroke = rel.lineColor || '#94a3b8'; // ★No.220-5: リレーションシップの LineColor
if (idef) {
// IDEF1X: 依存 (Dependence=1) は実線、 非依存は破線 (A5M2 は UseNondependenceDashLine の値に
// 関わらず IDEF1X 表示では非依存を破線で描く — 実測)
// ★No.239: 両端が「多」(多対多 = 非特定関係) は IDEF1X でも実線 (astah の表示に合わせる)
var m2m = /^[345]$/.test(String(rel.rt1 || '')) && /^[345]$/.test(String(rel.rt2 || ''));
s += '<polyline points="' + route + '" fill="none" stroke="' + rstroke + '" stroke-width="1.3"' +
((rel.dep === '1' || m2m) ? '' : ' stroke-dasharray="6,4"') + '/>';
s += markerIdef(e1.x, e1.y, e1.ox, e1.oy, rel.rt1 || '1', rel.card1, false);
s += markerIdef(e2.x, e2.y, e2.ox, e2.oy, rel.rt2 || '3', rel.card2, true);
} else {
// ★No.230: IE は A5M2 の UseNondependenceDashLine=1 のときだけ非依存を破線 (OBER 変換はこれを 1 で書く)
s += '<polyline points="' + route + '" fill="none" stroke="' + rstroke + '" stroke-width="1.3"' +
((nonDepDash && rel.dep !== '1') ? ' stroke-dasharray="6,4"' : '') + '/>';
s += marker(e1.x, e1.y, e1.ox, e1.oy, rel.rt1 || '1', rel.card1);
s += marker(e2.x, e2.y, e2.ox, e2.oy, rel.rt2 || '3', rel.card2);
}
if (rel.caption) s += routeCaption(route, rel.caption); // ★Ver1.0.22 (No.201): リレーションシップ名 (A5M2 は線の横に表示)
}
// ★No.218: 親か子の片方だけがこのページに居るリレーション = A5M2 の ShowPageoutRelation (相手の名前つきの短い線を右へ)
if (page != null) {
for (ri = 0; ri < model.relations.length; ri++) {
var por = model.relations[ri], pg1 = geom[por.e1], pg2 = geom[por.e2];
if ((pg1 && pg2) || (!pg1 && !pg2) || por.e1 === por.e2) continue;
var here = pg1 || pg2, isParentHere = !!pg1, partner = isParentHere ? por.e2 : por.e1;
if (here.isSub) continue;
var pe0 = model.byPName ? model.byPName[partner] : null, pname0 = pe0 ? (pe0.lname || pe0.pname) : partner;
if (!pe0 && !(model.byPName && model.byPName[partner] === undefined)) continue;
var ep = endpoint(here, isParentHere ? firstField(por.f1) : firstField(por.f2), { x: here.x + here.w + 200, y: here.y, w: 10, h: here.h }, null);
var sx2 = ep.x + 40, pdash = (idef ? por.dep !== '1' : (nonDepDash && por.dep !== '1')) ? ' stroke-dasharray="6,4"' : '';
s += '<polyline points="' + ep.x + ',' + ep.y + ' ' + sx2 + ',' + ep.y + '" fill="none" stroke="' + (por.lineColor || '#94a3b8') + '" stroke-width="1.3"' + pdash + '/>';
var prt = isParentHere ? (por.rt1 || '1') : (por.rt2 || '3'), pcard = isParentHere ? por.card1 : por.card2;
s += idef ? markerIdef(ep.x, ep.y, ep.ox, ep.oy, prt, pcard, !isParentHere) : marker(ep.x, ep.y, ep.ox, ep.oy, prt, pcard);
s += '<text x="' + (sx2 + 3) + '" y="' + (ep.y + 3.5) + '" font-size="9.5" fill="#475569">' + _erEsc(pname0) + '</text>';
}
}
// サブタイプ・クラスタをツリー状に描画 (親→記号→バス→各サブタイプ)
for (var sk = 0; sk < model.subtypes.length; sk++) {
var snode = model.subtypes[sk]; var gS = geom[snode.pname];
if (!gS) continue;
var symCx = gS.x + gS.w / 2, symTop = gS.y, symBottom = gS.y + gS.h;
var sup = null, subs = [], subDash = [], supCaption = '', supDash = '';
// ★No.257: サブタイプの線も 依存 (Dependence=1) = 実線 / 非依存 = 破線 (A5M2 の IDEF1X 表示。 IE は UseNondependenceDashLine=1 のときだけ = 通常の関連と同じ規則)
var subDashOf = function (r) { return (idef ? r.dep !== '1' : (nonDepDash && r.dep !== '1')) ? ' stroke-dasharray="6,4"' : ''; };
for (var sri = 0; sri < model.relations.length; sri++) {
var sr = model.relations[sri];
var other = (sr.e1 === snode.pname) ? sr.e2 : (sr.e2 === snode.pname ? sr.e1 : null);
if (!other) continue;
var go = geom[other]; if (!go || go.isSub) continue;
if (go.y + go.h / 2 < gS.y) { sup = go; supDash = subDashOf(sr); if (sr.caption) supCaption = sr.caption; } else { subs.push(go); subDash.push(subDashOf(sr)); }
}
// 親(スーパータイプ) → 記号上端
if (sup) {
var supCx = sup.x + sup.w / 2, supBottom = sup.y + sup.h;
var midY = (supBottom + symTop) / 2;
s += '<polyline points="' + supCx + ',' + supBottom + ' ' + supCx + ',' + midY + ' ' + symCx + ',' + midY + ' ' + symCx + ',' + symTop +
'" fill="none" stroke="#94a3b8" stroke-width="1.3"' + supDash + '/>';
// ★Ver1.0.22 (No.201): 判別属性 (親→記号の関連の Caption) を親からの縦線の右に (A5M2 と同じ)
if (supCaption) s += '<text x="' + Math.round(supCx + 5) + '" y="' + Math.round((supBottom + midY) / 2 + 3.5) + '" font-size="9.5" fill="#475569">' + _erEsc(supCaption) + '</text>';
}
// 記号下端 → バス → 各サブタイプ上端
if (subs.length) {
var minTop = 1e9, allDash = subDash[0]; // ★No.257: 幹とバスは全部のサブタイプが非依存のときだけ破線 (混在なら実線)
for (var su = 0; su < subs.length; su++) { if (subs[su].y < minTop) minTop = subs[su].y; if (subDash[su] !== allDash) allDash = ''; }
var busY = (symBottom + minTop) / 2;
s += '<line x1="' + symCx + '" y1="' + symBottom + '" x2="' + symCx + '" y2="' + busY + '" stroke="#94a3b8" stroke-width="1.3"' + allDash + '/>';
var minX = symCx, maxX = symCx;
for (var su2 = 0; su2 < subs.length; su2++) { var cxv = subs[su2].x + subs[su2].w / 2; if (cxv < minX) minX = cxv; if (cxv > maxX) maxX = cxv; }
s += '<line x1="' + minX + '" y1="' + busY + '" x2="' + maxX + '" y2="' + busY + '" stroke="#94a3b8" stroke-width="1.3"' + allDash + '/>';
for (var su3 = 0; su3 < subs.length; su3++) { var scx = subs[su3].x + subs[su3].w / 2; s += '<line x1="' + scx + '" y1="' + busY + '" x2="' + scx + '" y2="' + subs[su3].y + '" stroke="#94a3b8" stroke-width="1.3"' + subDash[su3] + '/>'; }
}
}
// サブタイプ記号 (排他=○+X のような丸屋根+X)
for (var sj = 0; sj < psubs.length; sj++) {
var sn = psubs[sj]; if (sn.x == null) continue;
var sx = X(sn.x), sy = Y(sn.y), sw = sn.w || 60, sh = sn.h || 44;
if (idef) {
// IDEF1X のカテゴリ記号: ○ + 下線 1 本 (未確定) / 2 本 (確定カテゴリ CompleteCategory=1)
var ccr = Math.max(6, Math.min(sw, sh) * 0.32), ccx = sx + sw / 2, ccy = sy + sh * 0.42;
s += '<circle cx="' + ccx + '" cy="' + ccy + '" r="' + ccr + '" fill="#ffffff" stroke="#334155" stroke-width="1.3"/>';
s += '<line x1="' + (ccx - ccr) + '" y1="' + (ccy + ccr + 3) + '" x2="' + (ccx + ccr) + '" y2="' + (ccy + ccr + 3) + '" stroke="#334155" stroke-width="1.3"/>';
if (sn.complete === '1') s += '<line x1="' + (ccx - ccr) + '" y1="' + (ccy + ccr + 7) + '" x2="' + (ccx + ccr) + '" y2="' + (ccy + ccr + 7) + '" stroke="#334155" stroke-width="1.3"/>';
continue;
}
s += '<path d="M' + sx + ',' + (sy + sh) + ' L' + sx + ',' + (sy + sh * 0.45) +
' A' + (sw / 2) + ',' + (sh * 0.45) + ' 0 0 1 ' + (sx + sw) + ',' + (sy + sh * 0.45) +
' L' + (sx + sw) + ',' + (sy + sh) + ' Z" fill="#ffffff" stroke="#334155" stroke-width="1.3"/>';
if (sn.complete === '1') { // ★No.225: IE のカテゴリ記号の × は確定 (CompleteCategory=1) のときだけ (A5M2 の IE 表示と同じ。 従来は排他で描いていた)
s += '<line x1="' + (sx + 6) + '" y1="' + (sy + sh * 0.55) + '" x2="' + (sx + sw - 6) + '" y2="' + (sy + sh - 4) + '" stroke="#334155" stroke-width="1.1"/>';
s += '<line x1="' + (sx + sw - 6) + '" y1="' + (sy + sh * 0.55) + '" x2="' + (sx + 6) + '" y2="' + (sy + sh - 4) + '" stroke="#334155" stroke-width="1.1"/>';
}
}
// エンティティ
for (var ei = 0; ei < ents.length; ei++) {
var en = ents[ei]; if (en.x == null) continue;
var gE = geom[en.pname] || {};
var x = X(en.x), y = Y(en.y), bw = gE.w || en.w || 160, bh = gE.h || en.h || 80; // No.216: 自動サイズは geom で決めた値
var c = card(en.lname);
var rowH = gE.rowH || Math.max(13, Math.min(18, (bh - 26) / (en.attrs.length || 1)));
var ordered = gE.ordered || en.attrs;
var pkCount = gE.pkCount || 0;
// ★テスター指摘 No.97: Color (前景=枠/ヘッダ) / BkColor (背景) を反映。
// 未指定 ($FFFFFFFF/黒/白の既定 または キー無し) は従来スタイル (byte 同一)。
var _accent = en.color || '#4f46e5';
var _bodyFill = en.bkColor || '#ffffff';
if (String(en.effectMode || '').toLowerCase() === 'gradation') {
// ★No.246: A5M2 の EffectMode=Gradation は左端が背景色 (BkColor)、 右へ向かって白くなる横方向の濃淡 (向きや色の指定は無い)
var _gid = 'tfcgr-' + String(en.pname || '').replace(/[^A-Za-z0-9_-]/g, '_') + '-' + Math.round(x) + '-' + Math.round(y) + '-' + _bodyFill.replace(/[^0-9A-Fa-f]/g, '');
s += '<defs><linearGradient id="' + _gid + '" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="' + _bodyFill + '"/>' +
'<stop offset="1" stop-color="#ffffff"/></linearGradient></defs>';
_bodyFill = 'url(#' + _gid + ')';
}
if (idef || depSet[en.pname]) {
// 従属エンティティ (依存リレーションの子) は角丸 (A5M2 は IE / IDEF1X どちらでも — No.200)。 IDEF1X の独立エンティティは角無し
var _rx = depSet[en.pname] ? 10 : 0;
s += '<rect x="' + x + '" y="' + y + '" width="' + bw + '" height="' + bh + '" rx="' + _rx + '" fill="' + _bodyFill + '" stroke="' + _accent + '" stroke-width="1.3"/>';
if (_rx) {
s += '<path d="M' + (x + _rx) + ',' + y + ' h' + (bw - 2 * _rx) + ' a' + _rx + ',' + _rx + ' 0 0 1 ' + _rx + ',' + _rx +
' v' + (22 - _rx) + ' h-' + bw + ' v-' + (22 - _rx) + ' a' + _rx + ',' + _rx + ' 0 0 1 ' + _rx + ',-' + _rx + ' z" fill="' + _accent + '"/>';
} else {
s += '<rect x="' + x + '" y="' + y + '" width="' + bw + '" height="22" fill="' + _accent + '"/>';
}
} else {
// ★No.231: IE の独立エンティティも角無しの四角 (A5M2 / OBER / astah の IE 表示。 従来の rx=3 は従属 (角丸) と見分けにくかった)
s += '<rect x="' + x + '" y="' + y + '" width="' + bw + '" height="' + bh + '" fill="' + _bodyFill + '" stroke="' + _accent + '" stroke-width="1.3"/>';
s += '<rect x="' + x + '" y="' + y + '" width="' + bw + '" height="22" fill="' + _accent + '"/>';
}
// No.97: Tag (種類分け) はボックス右上に小さくバッジ表示
if (en.tag) {
s += '<text x="' + (x + bw - 4) + '" y="' + (y - 4) + '" font-size="9" fill="#64748b" text-anchor="end">' +
_erEsc('◈ ' + en.tag) + '</text>';
}
var title = _erEsc(en.lname || en.pname || '');
var tx = x + bw / 2, ty = y + 15;
if (c) {
var cKey = c.key || c.cd; // ★Ver1.0.22 (No.206): 物理名が同じ別エンティティと衝突しない一意キー (レジストリ ent.key)
matchedEntityCds[cKey] = (matchedEntityCds[cKey] || 0) + 1;
s += '<a href="EDM.html#edm-ent-' + _erEscAttr(cKey) + '" target="_top"><text x="' + tx + '" y="' + ty +
'" font-size="11.5" font-weight="bold" fill="#ffffff" text-anchor="middle">' + title + '</text></a>';
} else {
s += '<text x="' + tx + '" y="' + ty + '" font-size="11.5" font-weight="bold" fill="#ffffff" text-anchor="middle">' + title + '</text>';
}
// PK ブロック直後に横線 (A5M2 同様、 PK のみのエンティティでも常に引く)。 PK 表示・下線は不要
if (pkCount > 0) {
var sepY = Math.round(y + 22 + rowH * pkCount);
if (sepY < y + bh - 1) {
s += '<line x1="' + x + '" y1="' + sepY + '" x2="' + (x + bw) + '" y2="' + sepY + '" stroke="#4f46e5" stroke-width="0.8"/>';
}
}
var fy = y + 22 + rowH * 0.8;
for (var ai = 0; ai < ordered.length; ai++) {
var a = ordered[ai];
if (fy > y + bh - 2) break;
var isFk = !!fkSet[en.pname + '|' + a.pname];
var label = _erEsc(a.lname + (isFk ? ' (FK)' : '')) +
(showTypes && a.typeRaw ? '<tspan fill="#64748b" font-size="9.5"> ' + _erEsc(a.typeRaw) + '</tspan>' : ''); // ★No.220-9: 表示モード 3 = 属性とデータ型
// 図のリンクは常に EDM レジストリへ (図→レジストリ→ドメインの一本道)。
if (c) {
if (c.attrByName) { var ra = c.attrByName[_emNorm(a.lname)]; if (ra && ra.domCd) matchedDomainCds[ra.domCd] = (matchedDomainCds[ra.domCd] || 0) + 1; }
s += '<a href="EDM.html#edm-ent-' + _erEscAttr(c.key || c.cd) + '" target="_top"><text x="' + (x + 7) + '" y="' + Math.round(fy) + // ★No.206 確認NG (2026-09-30): 属性行も一意キー
'" font-size="10.5" fill="#1e40af">' + label + '</text></a>';
} else {
s += '<text x="' + (x + 7) + '" y="' + Math.round(fy) + '" font-size="10.5" fill="#1e293b">' + label + '</text>';
}
fy += rowH;
}
}
// ★テスター指摘 No.96: [View] をエンティティ風の破線ボックスで描画 (Query はツールチップ)
for (var vwi = 0; vwi < pviews.length; vwi++) {
var vw = pviews[vwi]; if (vw.x == null) continue;
var vcols = _a5erViewCols(vw.query); // ★No.220-8: A5M2 は Query の SELECT 句の列を表示する
var vx = X(vw.x), vy = Y(vw.y), vbw = vw.w || 160, vbh = vw.h || (22 + 16 * Math.max(1, vcols.length) + 6);
var vAccent = vw.color || '#0e7490';
var vFill = vw.bkColor || '#ffffff';
s += '<rect x="' + vx + '" y="' + vy + '" width="' + vbw + '" height="' + vbh +
'" rx="3" fill="' + vFill + '" stroke="' + vAccent + '" stroke-width="1.3" stroke-dasharray="5,3"/>';
s += '<rect x="' + vx + '" y="' + vy + '" width="' + vbw + '" height="22" rx="3" fill="' + vAccent + '"/>';
var vTitle = _erEsc(vw.lname || vw.pname || '');
// Query ツールチップ: 500 文字で切る。 境界がサロゲートペアの前半なら 1 文字戻す
// (孤立サロゲートは不正 XML 文字になるため)
var _vq = '';
if (vw.query) {
_vq = String(vw.query).substring(0, 500);
var _vqc = _vq.charCodeAt(_vq.length - 1);
if (_vqc >= 0xD800 && _vqc <= 0xDBFF) _vq = _vq.substring(0, _vq.length - 1);
}
s += '<text x="' + (vx + vbw / 2) + '" y="' + (vy + 15) +
'" font-size="11.5" font-weight="bold" fill="#ffffff" text-anchor="middle">' + vTitle +
(_vq ? '<title>' + _erEsc(_vq) + '</title>' : '') + '</text>';
s += '<text x="' + (vx + 6) + '" y="' + (vy + 13) + '" font-size="9" fill="#cffafe">V</text>';
for (var vci = 0; vci < vcols.length; vci++) {
var vcy = vy + 22 + 16 * (vci + 0.8);
if (vcy > vy + vbh - 2) break;
s += '<text x="' + (vx + 7) + '" y="' + Math.round(vcy) + '" font-size="10.5" fill="#1e293b">' + _erEsc(vcols[vci]) + '</text>';
}
}
// ★テスター指摘 No.96: [Comment] を付箋風に描画 (最前面)。 ZOrder を持つ注記は上の層で描画済み (No.199)
for (var cmi = 0; cmi < frontComments.length; cmi++) s += _a5erCommentSvg(frontComments[cmi], X, Y);
if (embed) {
return { svg: '', inner: s, W: W, H: H };
}
s += '</svg>';
return { svg: s, inner: '', W: W, H: H };
}
// [Comment] の SVG 描画 (No.96 の付箋 / 他ツールの注記)。 FontSize (pt) のある注記は元の比率で箱の幅で折り返して中央に
function _a5erCommentSvg(cm, X, Y) {
if (cm.left == null || cm.top == null) return '';
var s = '';
var cx0 = X(cm.left), cy0 = Y(cm.top), cw0 = cm.width || 160, ch0 = cm.height || 60;
s += '<rect x="' + cx0 + '" y="' + cy0 + '" width="' + cw0 + '" height="' + ch0 +
'" fill="' + (cm.bkColor || '#fefce8') + '" stroke="' + (cm.lineColor || '#d4b106') + '" stroke-width="1"/>';
var cmLines = String(cm.comment || '').split('\n'); // パーサで逆エスケープ済
if (cm.fontSize > 0 && !cm.fontName) { // ★No.220-7: A5M2 が書いた注記 (FontName あり) は左上寄せのまま。 中央寄せは astah 由来 (FontName 無し) だけ
// FontSize (pt) のある注記 (他ツールから変換した見出し等): 元の比率 (pt × 3.528 = 0.1mm) で、 箱の幅で折り返して縦横とも中央に
var bfs = cm.fontSize * 3.528, wrapped = [], wli;
for (wli = 0; wli < cmLines.length; wli++) {
var wsrc = cmLines[wli], wcur = '', wwid = 0;
for (var wci = 0; wci < wsrc.length; wci++) {
var wch = wsrc.charAt(wci), wcw = (wch.charCodeAt(0) > 0x2E7F) ? bfs : bfs * 0.55;
if (wcur && wwid + wcw > cw0 - 4) { wrapped.push(wcur); wcur = ''; wwid = 0; }
wcur += wch; wwid += wcw;
}
wrapped.push(wcur);
}
var blh = bfs * 1.15, bTop = cy0 + Math.max(0, (ch0 - wrapped.length * blh) / 2) + bfs * 0.9;
for (wli = 0; wli < wrapped.length; wli++) {
if (wli > 0 && bTop + wli * blh > cy0 + ch0) break; // 箱より大きい文字でも 1 行目は必ず描く
s += '<text x="' + Math.round(cx0 + cw0 / 2) + '" y="' + Math.round(bTop + wli * blh) + '" font-size="' + Math.round(bfs * 10) / 10 +
'" text-anchor="middle" fill="' + (cm.fontColor || '#334155') + '">' + _erEsc(wrapped[wli]) + '</text>';
}
return s;
}
var cmFs = 10.5, cmY = cy0 + cmFs + 4;
for (var cli = 0; cli < cmLines.length; cli++) {
if (cmY > cy0 + ch0 - 2) break;
s += '<text x="' + (cx0 + 6) + '" y="' + Math.round(cmY) + '" font-size="' + cmFs + (cm.fontBold ? '" font-weight="bold' : '') +
'" fill="' + (cm.fontColor || '#57534e') + '">' + _erEsc(cmLines[cli]) + '</text>';
cmY += cmFs + 3;
}
return s;
}
// [Shape] の SVG 描画 (No.96)。 基本図形 + フォールバック矩形。
function _a5erShapeSvg(sh, X, Y) {
if (sh.left == null || sh.top == null) return '';
var x = X(sh.left), y = Y(sh.top), w = sh.width || 40, h = sh.height || 40;
var stroke = sh.lineColor || '#334155';
var fill = sh.brushColor || '#ffffff';
var lw = sh.lineWidth || 1;
var _lsty = _a5erLineStyle(sh.lineType);
var dash = _lsty.dash;
var noLine = _lsty.hidden;
var alpha = (sh.brushAlpha != null && sh.brushAlpha >= 0 && sh.brushAlpha < 255)
? ' fill-opacity="' + (Math.round(sh.brushAlpha / 255 * 100) / 100) + '"' : '';
var common = ' fill="' + fill + '"' + alpha +
(noLine ? ' stroke="none"' : ' stroke="' + stroke + '" stroke-width="' + lw + '"' + dash);
var t = String(sh.shapeType || '').toLowerCase();
if (t === 'ellipse') {
return '<ellipse cx="' + (x + w / 2) + '" cy="' + (y + h / 2) + '" rx="' + (w / 2) + '" ry="' + (h / 2) + '"' + common + '/>';
}
if (t === 'round') { // ★No.244: 仕様書 4.5 の Round = 円 (枠に収まる円。 No.220 で角丸にしたのは誤り — RoundRect が角丸四角)
var rc = Math.min(w, h) / 2;
return '<circle cx="' + (x + w / 2) + '" cy="' + (y + h / 2) + '" r="' + rc + '"' + common + '/>';
}
if (t === 'roundrect') { // 角丸四角 (丸み = 短辺の 2 割)
var r0 = Math.round(Math.min(w, h) * 0.2);
return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" rx="' + r0 + '" ry="' + r0 + '"' + common + '/>';
}
if (t === 'stickman') { // ★No.245: 棒人間 = 頭の丸 + 腕 (横線) + 胴 (縦線) + 足 (下へ開く 2 本)。 塗り無し
var scx = x + w / 2, hr = Math.max(3, Math.min(w, h) / 8), hy = y + hr + lw, neck = hy + hr, hip = y + h * 0.65, arm = y + h * 0.4, span = w * 0.3;
var sm = ' fill="none"' + (noLine ? ' stroke="none"' : ' stroke="' + stroke + '" stroke-width="' + lw + '"' + dash);
return '<g class="tfc-stickman">' +
'<circle cx="' + scx + '" cy="' + hy + '" r="' + hr + '"' + sm + '/>' +
'<line x1="' + scx + '" y1="' + neck + '" x2="' + scx + '" y2="' + hip + '"' + sm + '/>' +
'<line x1="' + (scx - span) + '" y1="' + arm + '" x2="' + (scx + span) + '" y2="' + arm + '"' + sm + '/>' +
'<line x1="' + scx + '" y1="' + hip + '" x2="' + (scx - span) + '" y2="' + (y + h) + '"' + sm + '/>' +
'<line x1="' + scx + '" y1="' + hip + '" x2="' + (scx + span) + '" y2="' + (y + h) + '"' + sm + '/>' +
'</g>';
}
if (t === 'cross') {
return '<line x1="' + x + '" y1="' + y + '" x2="' + (x + w) + '" y2="' + (y + h) + '" stroke="' + stroke + '" stroke-width="' + lw + '"' + dash + '/>' +
'<line x1="' + (x + w) + '" y1="' + y + '" x2="' + x + '" y2="' + (y + h) + '" stroke="' + stroke + '" stroke-width="' + lw + '"' + dash + '/>';
}
if (t === 'allowupper' || t === 'allowlower' || t === 'allowleft' || t === 'allowright') {
// 矢印: 向きに応じた 7 点ポリゴン (軸太さ 1/3)
var pts;
var cx1 = x + w / 2, cy1 = y + h / 2, tw = w / 3, th = h / 3;
if (t === 'allowupper') pts = [[cx1, y], [x + w, y + h / 2], [cx1 + tw / 2, y + h / 2], [cx1 + tw / 2, y + h], [cx1 - tw / 2, y + h], [cx1 - tw / 2, y + h / 2], [x, y + h / 2]];
else if (t === 'allowlower') pts = [[cx1, y + h], [x, y + h / 2], [cx1 - tw / 2, y + h / 2], [cx1 - tw / 2, y], [cx1 + tw / 2, y], [cx1 + tw / 2, y + h / 2], [x + w, y + h / 2]];
else if (t === 'allowleft') pts = [[x, cy1], [x + w / 2, y], [x + w / 2, cy1 - th / 2], [x + w, cy1 - th / 2], [x + w, cy1 + th / 2], [x + w / 2, cy1 + th / 2], [x + w / 2, y + h]];
else pts = [[x + w, cy1], [x + w / 2, y + h], [x + w / 2, cy1 + th / 2], [x, cy1 + th / 2], [x, cy1 - th / 2], [x + w / 2, cy1 - th / 2], [x + w / 2, y]];
var ps = '';
for (var pi2 = 0; pi2 < pts.length; pi2++) ps += (pi2 ? ' ' : '') + Math.round(pts[pi2][0]) + ',' + Math.round(pts[pi2][1]);
return '<polygon points="' + ps + '"' + common + '/>';
}
if (t === 'database') {
var ry2 = Math.min(h / 5, 14);
return '<path d="M' + x + ',' + (y + ry2) + ' a' + (w / 2) + ',' + ry2 + ' 0 0 1 ' + w + ',0 v' + (h - 2 * ry2) +
' a' + (w / 2) + ',' + ry2 + ' 0 0 1 -' + w + ',0 z"' + common + '/>' +
'<ellipse cx="' + (x + w / 2) + '" cy="' + (y + ry2) + '" rx="' + (w / 2) + '" ry="' + ry2 +
'" fill="none"' + (noLine ? '' : ' stroke="' + stroke + '" stroke-width="' + lw + '"' + dash) + '/>';
}
return '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '"' + common + '/>';
}
// [Line] の SVG 描画 (No.96)。 (Left,Top) から (Left+Width, Top+Height) への線分。
function _a5erLineSvg(li, X, Y) {
if (li.left == null || li.top == null) return '';
var _lls = _a5erLineStyle(li.lineType);
if (_lls.hidden) return ''; // LineType=1 (線無し) — 従来は実線で描いていた
var x1 = X(li.left), y1 = Y(li.top);
var x2 = X(li.left + (li.width || 0)), y2 = Y(li.top + (li.height || 0));
var col = li.lineColor || '#334155', lw = li.lineWidth || 1;
var s = '<line x1="' + x1 + '" y1="' + y1 + '" x2="' + x2 + '" y2="' + y2 + '" stroke="' + col + '" stroke-width="' + lw + '"' + _lls.dash + '/>';
// ★No.220-3: 端の形 (A5M2 の StartLineTermType / EndLineTermType: 1 ○ / 2 ● / 3 → / 4 ▶ / 5 ◇ / 6 ◆ — 実物の表示で確認)
function term(tt, px, py, dx, dy) {
if (!tt) return '';
var len = Math.sqrt(dx * dx + dy * dy) || 1, ux = dx / len, uy = dy / len, qx = -uy, qy = ux, sz = 7 + lw;
if (tt === 1 || tt === 2) return '<circle cx="' + (px + ux * sz * 0.6) + '" cy="' + (py + uy * sz * 0.6) + '" r="' + (sz * 0.6) + '" fill="' + (tt === 2 ? col : '#ffffff') + '" stroke="' + col + '" stroke-width="' + lw + '"/>';
var bx = px + ux * sz * 1.6, by = py + uy * sz * 1.6;
if (tt === 3) return '<polyline points="' + (bx + qx * sz * 0.7) + ',' + (by + qy * sz * 0.7) + ' ' + px + ',' + py + ' ' + (bx - qx * sz * 0.7) + ',' + (by - qy * sz * 0.7) + '" fill="none" stroke="' + col + '" stroke-width="' + lw + '"/>';
if (tt === 4) return '<polygon points="' + px + ',' + py + ' ' + (bx + qx * sz * 0.7) + ',' + (by + qy * sz * 0.7) + ' ' + (bx - qx * sz * 0.7) + ',' + (by - qy * sz * 0.7) + '" fill="' + col + '" stroke="' + col + '" stroke-width="' + lw + '"/>';
var mx = px + ux * sz, my = py + uy * sz, fx = px + ux * sz * 2, fy = py + uy * sz * 2;
return '<polygon points="' + px + ',' + py + ' ' + (mx + qx * sz * 0.6) + ',' + (my + qy * sz * 0.6) + ' ' + fx + ',' + fy + ' ' + (mx - qx * sz * 0.6) + ',' + (my - qy * sz * 0.6) + '" fill="' + (tt === 6 ? col : '#ffffff') + '" stroke="' + col + '" stroke-width="' + lw + '"/>';
}
s += term(li.startTerm, x1, y1, x2 - x1, y2 - y1) + term(li.endTerm, x2, y2, x1 - x2, y1 - y2);
return s;
}
// ★No.220-2: [Shape] の Text (中央寄せ、 複数行)。 図形の上に重ねる
function _a5erShapeTextSvg(sh, X, Y) {
if (sh.left == null || sh.top == null || !sh.text) return '';
var x = X(sh.left), y = Y(sh.top), w = sh.width || 40, h = sh.height || 40;
var lines = String(sh.text).split('\n'), fs = sh.fontSize > 0 ? Math.max(9, Math.round(sh.fontSize * 1.2 * 10) / 10) : 10.5, lh = fs * 1.2;
var top = y + h / 2 - (lines.length - 1) * lh / 2 + fs * 0.35, s = '', i;
for (i = 0; i < lines.length; i++) {
s += '<text x="' + Math.round(x + w / 2) + '" y="' + Math.round(top + i * lh) + '" font-size="' + fs + (sh.fontBold ? '" font-weight="bold' : '') +
'" fill="' + (sh.fontColor || '#334155') + '" text-anchor="middle">' + _erEsc(lines[i]) + '</text>';
}
return s;
}
// ★No.220-8: [View] の Query の SELECT 句から列名を取り出す (A5M2 は Query の列を箱に表示する)。 別名 (AS x) > 修飾を外した名前
function _a5erViewCols(query) {
var q = String(query || '').replace(/\s+/g, ' ');
var m = /select\s+(?:distinct\s+)?([\s\S]*?)\s+from\s/i.exec(q);
if (!m) return [];
var items = [], depth = 0, cur = '', i, ch;
for (i = 0; i < m[1].length; i++) {
ch = m[1].charAt(i);
if (ch === '(') depth++; else if (ch === ')') depth--;
if (ch === ',' && depth === 0) { items.push(cur); cur = ''; } else cur += ch;
}
items.push(cur);
var out = [];
for (i = 0; i < items.length && out.length < 40; i++) {
var it = items[i].replace(/^\s+|\s+$/g, '');
if (!it) continue;
var am = /\s+as\s+("?[^"\s]+"?)$/i.exec(it);
var nm = am ? am[1] : (/\)\s*$/.test(it) ? it : it.replace(/^.*\./, ''));
out.push(nm.replace(/^"|"$/g, ''));
}
return out;
}
// LineType (0=実線 / 2=ダッシュ / 3=ダッシュドット / 4=ダッシュドットドット) → dasharray
function _a5erDash(lt) {
if (lt === 2) return ' stroke-dasharray="7,4"';
if (lt === 3) return ' stroke-dasharray="9,4,2,4"';
if (lt === 4) return ' stroke-dasharray="9,4,2,4,2,4"';
return '';
}
// LineType の統一判定 (1 = 線無し)。 Shape と Line で判定が二重実装になり
// Line 側だけ「線無し」を実線で描いてしまっていたのを共通化。
function _a5erLineStyle(lt) {
return { hidden: lt === 1, dash: _a5erDash(lt) };
}
TFE.parseA5erModel = _parseA5er;
TFE.renderA5erToSvg = _renderA5erToSvg;
TFE.a5erContentPages = _a5erContentPages;
// ============================================================
// EDM メンテナンスのプレビュー SVG (Ver1.0.4)
//
// EDM メンテナンス画面で登録済み EDM の図をブラウザだけで確認できるようにする。
// ・生成タイミング: EDM メンテナンスの確定後 JS (0S101) だけ。 TALON はアップロード
// ファイルの書込 (uploadFile) を UPDATE_AFTER の呼出より前に行うので、 差替直後の
// .a5er を読める (ExecuteProcess で実測)。 SETUP では生成しない (導入時は EDM が無い。
// 既存環境は 何か 1 回確定すれば全行に付く)。
// ・置き場所と名前: TALON が保存した .a5er と同じフォルダに、 拡張子だけ .svg に替えた
// 同名ファイル (TLN_M_FUNC_EDM/SRC_FILE/TLN_M_FUNC_EDM_SRC_FILE_{EDM_CD}.svg)。
// 物理名は EDM コードから決まるので差替のたびに同名で上書きされる。
// ・表示: ブロック SELECT 式の REPLACE(SRC_FILE, '.a5er', '.svg') as SVG_VIEW (更新なしの
// FILE 型 + サムネイルサイズ) が この .svg を指す。 TALON の読み取り専用 FILE 項目は
// 項目値の物理パスをそのまま img の src にし (svg は本体のアイコン対応表に無い)、
// クリックで openImgWindow = window.open するので、 別ウィンドウに原寸表示される。
// ・ファイル形式: 単一 SVG。 width/height 属性 (img の縮小に固有サイズが要る) +
// 埋め込み script (直接開いたときだけ動く: フィット / ズーム / パン。 img では実行されない)。
// ・再生成の規則: 確定のたびに全行を見て、 SVG が無い / .a5er より古い / 生成版 (STAMP) が
// 古い 行だけ作る。 描画できない .a5er (エンティティ無し等) は既存 SVG を消す
// (= 画面は No Image になる)。 1 行の失敗は他の行と確定に影響させない。
// ・設計書出力 (EDM.html / EDM.md) は従来どおり出力時に .a5er から描く (この SVG は使わない)。
// ============================================================
// ★描画が変わったら版を上げる (v2 = IDEF1X 表記対応 / v3 = 複数ページの切替ボタン / v4 = 読込後の再フィット / v5 = ページ箱のフォールバック / v6 = ページ選択時に全体背景を非表示)。 古い版の SVG は次の EDM 確定で作り直される
var EDM_PREVIEW_STAMP = 'tfc-edm-preview v11'; // Ver1.0.22 (No.244〜247 図形 / No.252 リレーションシップ名の背景 / No.257 サブタイプの線の破線 / No.258 自己参照の C 字)
TFE.EDM_PREVIEW_STAMP = EDM_PREVIEW_STAMP;
// 直接表示時のビューア (ブラウザで実行される ES5。 CDATA に入れるので < や && をそのまま書ける)
// ・root svg を 100% にして viewBox の操作で フィット / ズーム (ホイール・ボタン・+/-/0 キー) /
// ドラッグでパン。 操作ボタン群 (#tfcEdmCtl、 静止画では display="none") は
// viewBox に合わせて逆スケールし、 画面上で常に同じ大きさに見せる。
var _EDM_PREVIEW_VIEWER_JS = [
'(function () {',
' var svg = document.documentElement;',
" if (!svg || String(svg.tagName).toLowerCase() !== 'svg') return;",
" var ctl = document.getElementById('tfcEdmCtl');",
" var vb0 = String(svg.getAttribute('viewBox') || '').split(/[\\s,]+/);",
' var W = parseFloat(vb0[2]), H = parseFloat(vb0[3]);',
' if (!(W > 0) || !(H > 0)) return;',
' var vb = { x: 0, y: 0, w: W, h: H };',
" svg.setAttribute('width', '100%');",
" svg.setAttribute('height', '100%');",
" svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');",
" svg.style.background = '#e2e8f0';",
" svg.style.cursor = 'grab';",
" var tt = svg.firstElementChild;",
" if (tt && String(tt.tagName).toLowerCase() === 'title') document.title = tt.textContent;",
' function cw() { return svg.clientWidth || window.innerWidth || 1; }',
' function ch() { return svg.clientHeight || window.innerHeight || 1; }',
' function upp() { return Math.max(vb.w / cw(), vb.h / ch()); }',
' function origin() {',
' var s = upp(), vw = cw() * s, vh = ch() * s;',
' return { x: vb.x - (vw - vb.w) / 2, y: vb.y - (vh - vb.h) / 2, s: s };',
' }',
' function apply() {',
" svg.setAttribute('viewBox', vb.x + ' ' + vb.y + ' ' + vb.w + ' ' + vb.h);",
' if (ctl) {',
' var o = origin();',
" ctl.setAttribute('transform', 'translate(' + (o.x + 10 * o.s) + ' ' + (o.y + 10 * o.s) + ') scale(' + o.s + ')');",
' }',
' }',
' function zoomAt(f, px, py) {',
' var o = origin();',
' var ux = o.x + px * o.s, uy = o.y + py * o.s;',
' vb.x = ux - (ux - vb.x) / f; vb.y = uy - (uy - vb.y) / f;',
' vb.w = vb.w / f; vb.h = vb.h / f;',
' apply();',
' }',
// ページ切替 (複数ページの図 = <g class="tfc-a5er-page">): 選んだページだけ表示してそのページに全体表示。 -1 = 全ページ (縦積み)
' var pgs = svg.querySelectorAll("g.tfc-a5er-page"), cur = -1;',
// ページの箱: data-y/w/h (無ければ入れ子 <svg> の y/width/height、 それも無ければ getBBox) — 属性が取れない環境でも全体にならないよう多段で求める
' function pageBox(i) {',
' var g = pgs[i], y = parseFloat(g.getAttribute("data-y")), w = parseFloat(g.getAttribute("data-w")), h = parseFloat(g.getAttribute("data-h"));',
' if (!(w > 0) || !(h > 0)) { var inner = g.querySelector("svg"); if (inner) { var iy = parseFloat(inner.getAttribute("y")) || 0; y = iy - 26; w = parseFloat(inner.getAttribute("width")); h = (parseFloat(inner.getAttribute("height")) || 0) + 26; } }',
' if (!(w > 0) || !(h > 0)) { try { var bb = g.getBBox(); y = bb.y; w = bb.width; h = bb.height; } catch (e) {} }',
' return { x: 0, y: (y > 0 ? y : 0), w: (w > 0 ? w : W), h: (h > 0 ? h : H) };',
' }',
' function fit() { var b = (cur >= 0 && cur < pgs.length) ? pageBox(cur) : { x: 0, y: 0, w: W, h: H }; vb = { x: b.x, y: b.y, w: b.w, h: b.h }; apply(); }',
' function showPage(i) {',
' cur = (i >= 0 && i < pgs.length) ? i : -1;',
' for (var k = 0; k < pgs.length; k++) pgs[k].setAttribute("display", (cur < 0 || k === cur) ? "inline" : "none");',
// ★全ページ分の淡い背景 (合成 SVG の背景矩形) はページ選択時には消す — 縮小したときに他ページ分の空白が見えないように (2026-09-19 ユーザー指摘)
' var bg = svg.querySelector("rect.tfc-a5er-bg"); if (bg) bg.setAttribute("display", cur < 0 ? "inline" : "none");',
' var bs = ctl ? ctl.querySelectorAll("[data-page-idx]") : [];',
' for (var b2 = 0; b2 < bs.length; b2++) { var on = String(bs[b2].getAttribute("data-page-idx")) === String(cur); var rc = bs[b2].querySelector("rect"); if (rc) rc.setAttribute("fill", on ? "#c7d2fe" : "#ffffff"); }',
' fit();',
' }',
' function natural() {',
' var cx = vb.x + vb.w / 2, cy = vb.y + vb.h / 2;',
' vb.w = cw(); vb.h = ch(); vb.x = cx - vb.w / 2; vb.y = cy - vb.h / 2;',
' apply();',
' }',
" var acts = { 'in': function () { zoomAt(1.25, cw() / 2, ch() / 2); },",
" 'out': function () { zoomAt(1 / 1.25, cw() / 2, ch() / 2); },",
" 'fit': fit, 'nat': natural };",
' if (ctl) {',
" ctl.setAttribute('display', 'inline');",
" var btns = ctl.querySelectorAll('[data-act]');",
' for (var i = 0; i < btns.length; i++) {',
' (function (b) {',
" b.addEventListener('click', function (e) {",
' e.stopPropagation(); e.preventDefault();',
" var a = acts[b.getAttribute('data-act')]; if (a) a();",
' });',
" b.addEventListener('mousedown', function (e) { e.stopPropagation(); });",
' })(btns[i]);',
' }',
' }',
' if (ctl && pgs.length > 1) {',
' var NS = "http://www.w3.org/2000/svg", x0 = 142;',
' var mk = function (label, idx) {',
' var g = document.createElementNS(NS, "g"); g.setAttribute("data-page-idx", idx); g.setAttribute("style", "cursor:pointer");',
' var r = document.createElementNS(NS, "rect"); r.setAttribute("y", "0"); r.setAttribute("height", "26"); r.setAttribute("rx", "4"); r.setAttribute("fill", "#ffffff"); r.setAttribute("stroke", "#94a3b8"); r.setAttribute("stroke-width", "1");',
' var t = document.createElementNS(NS, "text"); t.setAttribute("x", "7"); t.setAttribute("y", "18"); t.setAttribute("font-size", "12"); t.setAttribute("fill", "#334155"); t.textContent = label;',
' g.appendChild(r); g.appendChild(t); ctl.appendChild(g);',
' var tw = 0; try { tw = t.getComputedTextLength(); } catch (e) { tw = 0; }',
' if (!(tw > 0)) tw = label.length * 12;',
' var w = Math.max(30, Math.ceil(tw) + 14); r.setAttribute("width", w); g.setAttribute("transform", "translate(" + x0 + " 0)"); x0 += w + 4;',
' g.addEventListener("click", function (e) { e.stopPropagation(); e.preventDefault(); showPage(idx); });',
' g.addEventListener("mousedown", function (e) { e.stopPropagation(); });',
' };',
' mk(ctl.getAttribute("data-all") || "ALL", -1);',
' for (var p = 0; p < pgs.length; p++) mk(pgs[p].getAttribute("data-page") || String(p + 1), p);',
' showPage(0);',
// ★ブラウザが読込完了後に viewBox / サイズを触る場合に備えて、 表示中ページへの全体表示を再適用する (2026-09-19)
" window.addEventListener('load', function () { fit(); });",
' setTimeout(fit, 150);',
' }',
" svg.addEventListener('wheel', function (e) {",
' e.preventDefault();',
' zoomAt(e.deltaY < 0 ? 1.15 : 1 / 1.15, e.clientX, e.clientY);',
' }, { passive: false });',
' var drag = null;',
" svg.addEventListener('mousedown', function (e) {",
' if (e.button !== 0) return;',
' drag = { x: e.clientX, y: e.clientY, vx: vb.x, vy: vb.y, s: upp() };',
" svg.style.cursor = 'grabbing'; e.preventDefault();",
' });',
" window.addEventListener('mousemove', function (e) {",
' if (!drag) return;',
' vb.x = drag.vx - (e.clientX - drag.x) * drag.s;',
' vb.y = drag.vy - (e.clientY - drag.y) * drag.s;',
' apply();',
' });',
" window.addEventListener('mouseup', function () { drag = null; svg.style.cursor = 'grab'; });",
" window.addEventListener('resize', apply);",
" window.addEventListener('keydown', function (e) {",
" if (e.key === '+' || e.key === '=') acts['in']();",
" else if (e.key === '-') acts['out']();",
" else if (e.key === '0') fit();",
" else if (e.key === 'PageDown' && pgs.length > 1) showPage(cur + 1 < pgs.length ? cur + 1 : 0);",
" else if (e.key === 'PageUp' && pgs.length > 1) showPage(cur > 0 ? cur - 1 : pgs.length - 1);",
' });',
' if (!(pgs.length > 1)) fit();',
'})();'
].join('\n');
// 操作ボタン群 (静止画では非表示)。 30x26 px の角丸ボタン 4 つ: + / − / 全体 / 1:1
function _edmPreviewCtlSvg(lang) {
function btn(x, w, act, glyph, tipKey) {
return '<g data-act="' + act + '" style="cursor:pointer" transform="translate(' + x + ' 0)">' +
'<title>' + _erEsc(_erT(tipKey, lang)) + '</title>' +
'<rect x="0" y="0" width="' + w + '" height="26" rx="4" fill="#ffffff" stroke="#94a3b8" stroke-width="1"/>' +
'<text x="' + (w / 2) + '" y="18" text-anchor="middle" font-size="14" fill="#334155">' + glyph + '</text></g>';
}
return '<g id="tfcEdmCtl" display="none" data-all="' + _erEscAttr(_erT('edmPrev.allPages', lang)) + '" font-family="\'Segoe UI\',\'Meiryo\',sans-serif">' +
btn(0, 30, 'in', '+', 'edmPrev.zoomIn') +
btn(34, 30, 'out', '−', 'edmPrev.zoomOut') +
btn(68, 30, 'fit', '⊡', 'edmPrev.fit') +
btn(102, 36, 'nat', '1:1', 'edmPrev.natural') +
'</g>';
}
// 描画済み SVG (TFC.renderA5erToSvg の svg) をプレビュー用の単一ファイルに仕立てる (★純関数)。
// ・XML 宣言 + STAMP コメント (再生成要否の判定用)
// ・root に width/height (viewBox と同値。 img の max-width/max-height での縮小に必要)
// ・<title> (直接開いたときのタブ名) + 操作ボタン群 + ビューア script
// 戻り: ファイル全文。 入力が空 / viewBox 無しなら ''
function _tfcEdmPreviewSvg(svgText, title, lang) {
var src = _erS(svgText);
var m = /^\s*<svg\b([^>]*)>/.exec(src);
if (!m) return '';
var vbm = /viewBox\s*=\s*"\s*([\d.+-]+)[\s,]+([\d.+-]+)[\s,]+([\d.+-]+)[\s,]+([\d.+-]+)\s*"/.exec(m[1]);
if (!vbm) return '';
var W = parseFloat(vbm[3]), H = parseFloat(vbm[4]);
if (!(W > 0) || !(H > 0)) return '';
var openTag = m[0];
if (!/\swidth\s*=/.test(m[1])) {
openTag = openTag.replace(vbm[0], vbm[0] + ' width="' + W + '" height="' + H + '"');
}
var rest = src.substring(m[0].length);
var endIdx = rest.lastIndexOf('</svg>');
if (endIdx < 0) return '';
var inner = rest.substring(0, endIdx);
return '<?xml version="1.0" encoding="UTF-8"?>\n' +
'<!-- ' + EDM_PREVIEW_STAMP + ' -->\n' +
openTag +
'<title>' + _erEsc(_erS(title)) + '</title>' +
inner +
_edmPreviewCtlSvg(lang) +
'<script type="text/javascript"><![CDATA[\n' + _EDM_PREVIEW_VIEWER_JS + '\n]]></script>' +
'</svg>\n';
}
TFE.edmPreviewSvg = _tfcEdmPreviewSvg;
// FK 行 (列単位) を制約単位にグルーピング (複合 FK 対応)。
// 各方言クエリの ORDER BY (テーブル → 制約名 → 列位置) 順を保持する。
// 従来は列単位のまま出力しており、 複合 FK が DDL では同名 ALTER の複数発行 (2 本目が
// エラー)、 a5er では同一テーブル間の [Relation] 複数本になっていた。
// 制約名の無い行はグルーピングできないため 1 行 1 制約として扱う。
function _groupFks(fks) {
var out = [], byKey = {};
for (var i = 0; i < fks.length; i++) {
var f = fks[i];
var key = f.name ? (f.childTable + '' + f.name) : ('' + i);
var g = byKey[key];
if (!g) {
g = { name: f.name, childTable: f.childTable, parentTable: f.parentTable,
childCols: [], parentCols: [] };
byKey[key] = g; out.push(g);
}
g.childCols.push(f.childCol);
g.parentCols.push(f.parentCol);
}
return out;
}
// ============================================================
// A5:SQL Mk-2 ネイティブ形式 (.a5er) 生成
// ============================================================
// 公式仕様: A5:SQL Mk-2 (https://a5m2.mmatsubara.com/) の独自 INI 風テキスト形式。
// - 文字コード: UTF-8 (BOM 付き)
// - 改行: CRLF
// - ヘッダ + [Manager] + [Entity]* + [Relation]* セクション
// - Field 行: "論理名","物理名","型","制約",主キー順序(0始まり/非キー空),"","",$色,"コメント"
// - Relation 行: Entity1=親(1側) / Entity2=子(多側)、 Fields1/Fields2=親/子の関連列物理名
// (複合キーはカンマ連結)
// - 自動配置: テーブルを横 4 列 × 縦 N 行のグリッドに配置
function _erToA5er(meta) {
// レイアウト方針:
// 4 列固定 × 列ごとに Y を独立して詰めるパッキングレイアウト。
// 各エンティティのボックス高は HDR_H + (列数 × ROW_H) + FOOTER_H で算出し、
// 列数の多いテーブル (TLN_M_GENERAL_ITEM 等) が <続きあり> で切れないようにする。
// テーブル数が多くキャンバスから溢れる場合は、A5:SQL Mk-2 側で
// [設定 → ER図のプロパティ → 用紙サイズ/ページ数] を手動拡張する想定。
var ENT_W = 600, SP_X = 200, SP_Y = 100;
var HDR_H = 70; // テーブル名ヘッダ部 + 上余白
var ROW_H = 36; // 列 1 行あたりの logical unit (実測: 旧 ENT_H=500 / 13 列 ≈ 34)
var FOOTER_H = 30; // 下マージン + <続きあり> マーカー領域分
var MIN_H = 200; // 列が極端に少ない場合の最小高
var TOP0 = 100, LEFT0 = 100;
var _geom = { entW: ENT_W, spX: SP_X, spY: SP_Y, hdrH: HDR_H, rowH: ROW_H,
footerH: FOOTER_H, minH: MIN_H, top0: TOP0, left0: LEFT0 };
// ★テスター指摘 No.90: 用紙サイズと列数をセットで自動選択する。
// 初版 (2026-08-01) は 4 列固定のまま用紙だけ自動選択したため、 テーブルが増えると
// 縦にだけ伸びて A1 でも高さを超え、 横幅は余ったままだった (2026-08-04 再指摘)。
// → 小さい用紙から順に「その用紙幅に入る列数」で詰め直し、 収まった時点で確定する。
// どれにも収まらなければ最大用紙 (A1) の列数で出力する (A5M2 側でページ拡張可)。
var _PAPER_W = [2970, 4200, 5940, 8410]; // A4 / A3 / A2 / A1 Landscape の幅
var positions = null, _maxX = 0, _maxY = 0;
for (var pwI = 0; pwI < _PAPER_W.length; pwI++) {
var _cols = _a5erColsForPaper(_PAPER_W[pwI], ENT_W, SP_X, LEFT0);
var _packed = _a5erPack(meta.tables, _cols, _geom);
positions = _packed.positions;
_maxX = _packed.maxX;
_maxY = _packed.maxY;
// この用紙に収まったら確定 (収まらなければ次の大きい用紙で列数を増やして再配置)
if (_a5erPickPaper(_maxX, _maxY).w <= _PAPER_W[pwI]) break;
}
var _paper = _a5erPickPaper(_maxX, _maxY);
var N = meta.tables.length;
var L = [];
// ヘッダ
L.push('# A5:ER FORMAT:21');
L.push('# A5:ER ENCODING:UTF8');
L.push('# A5:ER Mk-1 Copyright © 2007 m.matsubara');
L.push('# A5:SQL Mk-2 Generated by TLN_FUNC_DOC_ER_DIAGRAM_COMMON');
L.push('# https://a5m2.mmatsubara.com');
L.push('');
// Manager セクション
L.push('[Manager]');
L.push('ProjectName=');
L.push('Author=');
L.push('MaxEntityRowShow=1000');
L.push('ReadOnlyRecommend=0');
// PageInfo="ページ名",表示モード,"用紙サイズ","背景色"。 表示モード 3 は A5M2 既定の
// シリアライズ値 (E2E で開けることを確認済み。 意味の公開仕様なし)
L.push('PageInfo="Main",3,"' + _paper.nm + '",$FFFFFF');
L.push('LogicalView=0');
L.push('DecodeDomain=0');
L.push('ViewFormat=0');
L.push('UseNondependenceDashLine=0');
L.push('FontName=Tahoma');
L.push('FontSize=9');
L.push('PaperSize=' + _paper.nm);
L.push('ShowPageoutRelation=1');
L.push('DefaultPkName=%0:s_PKC');
L.push('DefaultPkIndexName=%0:s_PKI');
L.push('DefaultIndexName=%0:s_IX%1:d');
L.push('DefaultFkName=%0:s_FK%1:d');
L.push('SqlSeparator=0');
L.push('UpperCaseKeyword=0');
L.push('ShowTag=1');
L.push('ShowCommonAttributes=0');
L.push('ShowDisableAttributes=0');
L.push('BugFixEntityWidth=1');
L.push('');
// Entities (事前計算した positions を使用)
var stamp = _a5erTimestamp();
for (var ti = 0; ti < N; ti++) {
var t = meta.tables[ti];
var p = positions[ti];
L.push('[Entity]');
L.push('PName=' + _a5erLine(t.name));
// ★テスター指摘 No.94: TALON のテーブルコメントは「論理名■補足説明」形式。
// LName には ■ より前 (論理名) だけを入れ、 補足は Comment に回す
// (従来は ■ 込みの全文を LName に入れ、 A5M2 で論理名が長大になっていた)。
// ★型の使い分け (公式仕様 §4.1 / §1.2): LName/PName は String (エスケープしない —
// \q 等を入れると A5M2 がそのまま表示してしまう)。 行形式を壊す改行/タブのみ
// 空白へ置換 (_a5erLine)。 Comment は EscapedString (§1.2 エスケープ対象)。
var _tc = _a5erSplitComment(t.comment);
L.push('LName=' + _a5erLine(_tc.lname || t.name));
L.push('Comment=' + _a5erStr(_tc.supp));
L.push('TableInnerOption=');
L.push('TableOption=');
L.push('Page=Main');
L.push('Left=' + p.left);
L.push('Top=' + p.top);
// ★テスター指摘 No.65: Field の5番目トークンは A5M2 仕様上「主キー順序」
// (0 始まり・非キー列は空)。 従来は PK フラグ (1/0) を出しており、 A5M2 で
// 編集・保存すると「リストのインデックスが範囲を超えています」で保存不能だった
// (非キー列の '0' を PK 順序 0 と誤認するため)。 PK 列に 0,1,2… を割当て、
// 非 PK 列は空にする。 順序は列出現順 (= 多くの場合キー定義順) で近似する。
var pkOrder = 0;
for (var ci = 0; ci < t.cols.length; ci++) {
var c = t.cols[ci];
var notNull = c.nullable ? '' : 'NOT NULL';
// Field="論理名","物理名","型","制約",主キー順序(0始まり/非キー空),"デフォルト値","コメント",$色,"オプション" (仕様書 4.1.1。 2026-10-02: コメントは 7 番目に訂正)
// 論理名 = USER_COL_COMMENTS / pg_description の列コメント。 無ければ物理名で代替
// ★No.94: 列コメントも「論理名■補足」形式。 論理名は ■ より前、 補足は
// 最終トークン (コメント) に回す。
var _cc = _a5erSplitComment(c.comment);
var pkTok = c.isPk ? String(pkOrder++) : '';
L.push('Field="' + _a5erStr(_cc.lname || c.name) + '","' + _a5erStr(c.name) +
'","' + _a5erStr(_a5erType(c)) + '","' + notNull + '",' +
pkTok + ',"","' + _a5erStr(_cc.supp) + '",$FFFFFFFF,""');
}
// ★テスター指摘 No.95: 索引 (IndexInfo 複合値 §4.1.2)。 PK 索引はクエリ側で除外済。
// "索引名",ユニークフラグ(0=非/1=ユニーク),"カラムリスト(カンマ区切り)","オプション"
var _tIdxs = t.indexes || [];
for (var xi2 = 0; xi2 < _tIdxs.length; xi2++) {
var _ix2 = _tIdxs[xi2];
L.push('IndexInfo="' + _a5erStr(_ix2.name) + '",' +
(_ix2.uniqCons ? 2 : (_ix2.unique ? 1 : 0)) + // §4.1.2: 2=ユニーク制約
',"' + _a5erStr(_ix2.cols.join(',')) + '",""');
}
L.push('EffectMode=None');
L.push('Color=$000000');
L.push('BkColor=$FFFFFF');
L.push('ModifiedDateTime=' + stamp);
L.push('Position="Main",' + p.left + ',' + p.top + ',' + ENT_W + ',' + p.height);
L.push('ZOrder=' + (ti + 1));
L.push('');
}
// Relations (FK) — 公式仕様 (a5er_specification.md):
// Entity1=親(1側) / Entity2=子(多側)、 Fields1/Fields2 は 親/子の関連カラム物理名。
// RelationType: 0=指定なし, 1=0または1, 2=1, 3=0以上, 4=1以上, 5=N個固定
// → FK は 親(1) 対 子(0以上) なので RelationType1=2 / RelationType2=3。
// ※テスター指摘 No.49: 旧実装は Entity1=子 + RelationType1=1 で親子と多重度が
// 逆転しており、 A5M2 で 1対多 が 多対1 に見えていた。
// ★複合 FK は 1 つの [Relation] に Fields をカンマ連結 (§4.2)。 従来は列単位で
// [Relation] が複数出て A5M2 で線が列数分引かれていた (_groupFks で制約単位化)。
var _a5FkGroups = _groupFks(meta.fks);
for (var fi = 0; fi < _a5FkGroups.length; fi++) {
var f = _a5FkGroups[fi];
L.push('[Relation]');
L.push('Entity1=' + f.parentTable);
L.push('Entity2=' + f.childTable);
L.push('RelationType1=2');
L.push('RelationType2=3');
L.push('Fields1=' + f.parentCols.join(','));
L.push('Fields2=' + f.childCols.join(','));
L.push('Cardinarity1=');
L.push('Cardinarity2=');
L.push('Position="MAIN",0,1438,8562,1812,R,R,""');
L.push('Dependence=0');
L.push('Caption=');
L.push('PName=');
L.push('LineMode=0');
L.push('Bar1=144');
L.push('Bar2=856');
L.push('Bar3=181');
L.push('TermPos1=R');
L.push('TermPos2=R');
L.push('ZOrder=' + (meta.tables.length + fi + 1));
L.push('');
}
// UTF-8 BOM () + CRLF 連結
return '' + L.join('\r\n');
}
function _a5erType(c) {
var t = String(c.type || '').toUpperCase();
if ((t === 'NUMBER' || t === 'NUMERIC' || t === 'DECIMAL') && c.prec) {
return t + '(' + c.prec + (c.scale && c.scale !== '0' ? ',' + c.scale : '') + ')';
}
if ((t.indexOf('CHAR') >= 0 || t.indexOf('VARCHAR') >= 0) && c.len && c.len !== '0') {
return t + '(' + c.len + ')';
}
return t || 'VARCHAR2';
}
// String 型プロパティ (LName= 等、 §1.2 エスケープ対象外) 用のサニタイザ。
// エスケープはしない (A5M2 が \q 等を復元しないため入れると表示が壊れる)。
// 行ベース形式を壊す改行/タブのみ空白へ置換する。
function _a5erLine(s) {
return String(s || '').replace(/[\r\n\t]+/g, ' ');
}
// ★テスター指摘 No.90: レイアウト最大座標 (0.1mm 単位) から収まる最小の用紙 (横) を選ぶ。
// 公式仕様: 描画エリアの上下左右 5mm は余白、 さらにオブジェクト位置は
// 「用紙サイズ - 1.0cm 以内」 → 利用可能域 = 用紙寸法×10 - 100。
// A1Landscape でも収まらない場合は A1Landscape のまま出力する (A5M2 側でページ数を
// 増やして調整可能)。 純関数 (jsunit の実コード抽出テスト対象 — tests/test_a5er_output.py)。
function _a5erPickPaper(maxX, maxY) {
var PAPERS = [
{ nm: 'A4Landscape', w: 2970, h: 2100 },
{ nm: 'A3Landscape', w: 4200, h: 2970 },
{ nm: 'A2Landscape', w: 5940, h: 4200 },
{ nm: 'A1Landscape', w: 8410, h: 5940 }
];
for (var pp = 0; pp < PAPERS.length; pp++) {
if (maxX < PAPERS[pp].w - 100 && maxY < PAPERS[pp].h - 100) return PAPERS[pp];
}
return PAPERS[PAPERS.length - 1];
}
// ★テスター指摘 No.90 (2026-08-04 再指摘): 用紙幅に入る列数を算出する。
// 従来は 4 列固定だったため、 テーブルが増えると縦にだけ伸びて 用紙の高さを超え、
// 横幅は余ったままだった (30 テーブルで縦超過 / 横は空き)。 用紙を大きくしても
// 列数が 4 のままでは同じ形で伸びるだけなので、 用紙幅に応じて列数を増やす。
// 利用可能幅 = 用紙幅 - 100 (公式仕様: オブジェクト位置は用紙サイズ - 1.0cm 以内)
// - left0 (左上の開始オフセット)
// n 列の所要幅 = n*entW + (n-1)*spX → n = floor((利用可能幅 + spX) / (entW + spX))
// 純関数 (jsunit の実コード抽出テスト対象 — tests/test_a5er_output.py)。
function _a5erColsForPaper(paperW, entW, spX, left0) {
var avail = paperW - 100 - left0;
var n = Math.floor((avail + spX) / (entW + spX));
return n < 1 ? 1 : n;
}
// ★No.90: 指定列数でテーブルを詰め、 位置と最大 X/Y を返す (列ごとに Y を独立して詰める)。
// 純関数 (jsunit の実コード抽出テスト対象)。
function _a5erPack(tables, cols, geom) {
var positions = [], colY = [], maxX = 0, maxY = 0;
for (var ci = 0; ci < cols; ci++) colY[ci] = geom.top0;
for (var ti = 0; ti < tables.length; ti++) {
var t = tables[ti];
var nc = (t.cols && t.cols.length) || 0;
var h = Math.max(geom.minH, geom.hdrH + nc * geom.rowH + geom.footerH);
var col = ti % cols;
var left = geom.left0 + col * (geom.entW + geom.spX);
var top = colY[col];
colY[col] = top + h + geom.spY;
positions[ti] = { left: left, top: top, height: h };
if (left + geom.entW > maxX) maxX = left + geom.entW;
if (top + h > maxY) maxY = top + h;
}
return { positions: positions, maxX: maxX, maxY: maxY };
}
// ★テスター指摘 No.94: TALON のコメント「論理名■補足説明」を分割する。
// lname が空 (コメント無し / 先頭が ■) の場合は呼出側で物理名等にフォールバックする。
// 純関数 (jsunit の実コード抽出テスト対象)。
function _a5erSplitComment(comment) {
var parts = _erS(comment).split('■');
return { lname: parts[0] || '', supp: parts.length > 1 ? parts.slice(1).join('■') : '' };
}
function _a5erStr(s) {
// ★テスター指摘 No.91: A5:SQL Mk-2 公式仕様 §1.2 (EscapedString / Complex 中の文字列) のエスケープ。
// 従来は CSV 風の "→"" だったが仕様と異なり、 コメントに改行や引用符があると
// A5M2 でファイルが壊れる/照合に失敗した。 正しくは \→\\ / "→\Q / '→\q /
// タブ→\t / 改行(CR/LF/CRLF)→\n (順序重要: バックスラッシュを最初に置換)。
return String(s || '')
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\Q')
.replace(/'/g, '\\q')
.replace(/\t/g, '\\t')
.replace(/\r\n|\r|\n/g, '\\n');
}
function _a5erTimestamp() {
var d = new Date();
function p(n) { n = '' + n; return n.length < 2 ? '0' + n : n; }
return '' + d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) +
p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds());
}
// [[EDMCONV-MODULE-BEGIN]] (テストはこの範囲を切り出す)
// ============================================================
// 他ツールの形式 → .a5er 変換 (Ver1.0.5〜)。 入口は _edmConvToA5er (OBER XML / Visio JSON / astah {asta:1, bytes})。
// EDM メンテナンスの直接アップロード (本体 TFC.ensureEdmModels、 Ver1.0.7) と回帰テスト (tests/test_ober_parse.py 等) から呼ぶ。
// ブラウザ完結の独立ページ (EDM 変換ツール) は Ver1.0.7 で廃止 (直接アップロードに統合)。
// ★Ver1.0.22: DDL (.sql) のアップロードは廃止 (ユーザー決定 2026-09-29。 DDL パーサ _ddlParse 一式を削除)。 対応外の平文は throw する。
// 設計書出力の ER 図 (物理 DB) の DDL 出力 (本体 _erToDdl) は別物で残る。
// ============================================================
// ---- SI Object Browser ER (.edm) ----
// .edm は整形式 XML (実測 ERD-VERSION=8): ERD > ENTITY (ID / L-NAME / P-NAME / DEPENDENT / COMMENT) > ATTR (ID / L-NAME / P-NAME /
// DATATYPE / LENGTH / SCALE / NULL (1=NOT NULL) / PK (1) / COMMENT) > FK (RELATION=関連 ID, ATTR=親属性 ID)、
// ERD > RELATION (ID / P-NAME / R-TYPE (0=依存: FK 属性が PK) / P-ENTITY / C-ENTITY / VERBP-C)、
// ERD > MODELVIEW (L-NAME) > ENTITY (ID / LEFT / TOP / RIGHT / BOTTOM = px) / RELATION (ID + POS 頂点)。
// ビュー = A5M2 のページ、 座標は px → 0.1mm (×2.65)。 ビューに無いエンティティは「(未配置)」ページに格子で置く
var _OBER_PX = 2.65;
function _xmlUnesc(s) {
return String(s).replace(/&(#x[0-9a-fA-F]+|#[0-9]+|amp|lt|gt|quot|apos);/g, function (m, e) {
if (e === 'amp') return '&';
if (e === 'lt') return '<';
if (e === 'gt') return '>';
if (e === 'quot') return '"';
if (e === 'apos') return "'";
var code = (e.charAt(1) === 'x' || e.charAt(1) === 'X') ? parseInt(e.substring(2), 16) : parseInt(e.substring(1), 10);
return isNaN(code) ? m : String.fromCharCode(code);
});
}
// 要素と属性だけを読む簡易 XML スキャナ (テキストノード不要。 DOMParser の無い Nashorn / Node でも同じ結果)。
// 属性値は "…" 固定 (OBER の出力)。 戻り: { tag:'#root', children:[{tag, attrs, children}] }
function _xmlScan(text) {
var s = String(text || '').replace(/^/, ''), root = { tag: '#root', attrs: {}, children: [] }, stack = [root], i = 0, n = s.length;
var tagRe = /^<(\/?)([A-Za-z_][\w.:-]*)((?:\s+[A-Za-z_][\w.:-]*\s*=\s*"[^"]*")*)\s*(\/?)>$/;
var attrRe = /([A-Za-z_][\w.:-]*)\s*=\s*"([^"]*)"/g;
while (i < n) {
var lt = s.indexOf('<', i);
if (lt < 0) break;
if (s.substr(lt, 4) === '<!--') { var ce = s.indexOf('-->', lt); i = ce < 0 ? n : ce + 3; continue; }
if (s.charAt(lt + 1) === '?' || s.charAt(lt + 1) === '!') { var pe = s.indexOf('>', lt); i = pe < 0 ? n : pe + 1; continue; }
var gt = s.indexOf('>', lt);
if (gt < 0) break;
var m = tagRe.exec(s.substring(lt, gt + 1));
i = gt + 1;
if (!m) continue;
if (m[1]) { if (stack.length > 1) stack.pop(); continue; }
var el = { tag: m[2], attrs: {}, children: [] }, am;
attrRe.lastIndex = 0;
while ((am = attrRe.exec(m[3]))) el.attrs[am[1]] = _xmlUnesc(am[2]);
stack[stack.length - 1].children.push(el);
if (!m[4]) stack.push(el);
}
return root;
}
/**
* SI Object Browser ER の .edm → 変換モデル。 純関数。 .edm でなければ null。
* @returns {kind:'ober', name, pages:[{name, entities, relations}], entities:[{id, pname, lname, comment, dependent,
* attrs:[{id, pname, lname, type, len, prec, scale, pk, notNull, comment}], pos:{page:{x,y,w,h}}}],
* relations:[{id, pname, parent, child, parentCols, childCols, dep, rt1, rt2, caption, pages:[]}], warnings, stats}
*/
// OBER の DATATYPE / LENGTH / SCALE を製品の列モデル (type / len / prec / scale) に正規化する (属性・ドメイン共用)
function _oberColor(v) {
var n = parseInt(String(v == null ? '' : v), 10);
if (isNaN(n) || n < 0) return ''; // 負数 = システム色 (clWindow 等) = 既定の白
var h = (n & 0xFFFFFF).toString(16).toUpperCase();
return '$' + ('000000' + h).slice(-6); // Delphi TColor は $00BBGGRR = A5M2 の BkColor と同じ並び
}
function _oberTypeInto(o, attrs) {
o.type = (attrs.DATATYPE || '').toUpperCase(); o.len = attrs.LENGTH || ''; o.prec = ''; o.scale = attrs.SCALE || '';
if (/^(DECIMAL|NUMERIC|NUMBER|DEC)$/.test(o.type)) { o.prec = o.len; o.len = ''; }
else if (!/CHAR|TEXT|CLOB|BINARY|BLOB|STRING/.test(o.type)) { o.len = ''; o.scale = ''; }
if (o.scale === '0') o.scale = '';
if (o.prec === '0') o.prec = '';
return o;
}
function _oberParse(text) {
var root = _xmlScan(text), erd = null;
for (var ri = 0; ri < root.children.length; ri++) if (root.children[ri].tag === 'ERD') { erd = root.children[ri]; break; }
if (!erd) return null;
var res = { kind: 'ober', name: erd.attrs['L-NAME'] || '', version: erd.attrs['ERD-VERSION'] || '', pages: [], entities: [], relations: [], subtypes: [],
warnings: [], stats: { tables: 0, columns: 0, fks: 0, pages: 0, subtypes: 0 } };
var entById = {}, attrById = {}, relById = {}, ci;
// ドメイン (DOMAIN 要素: 名前 / 物理名 / 型・桁 / 定義内容) → A5M2 の DomainInfo。 属性は DDOMAINID で参照する (Ver1.0.5)
var domById = {}, domByName = {};
res.domains = [];
for (ci = 0; ci < erd.children.length; ci++) {
var d0 = erd.children[ci];
if (d0.tag !== 'DOMAIN') continue;
var dm = _oberTypeInto({ id: d0.attrs.ID, name: d0.attrs['L-NAME'] || '', pname: d0.attrs['P-NAME'] || '',
comment: d0.attrs.COMMENT || '' }, d0.attrs);
if (!dm.name) continue;
if (domByName[dm.name]) { res.warnings.push('DOMAIN ' + dm.name + ': 同名のドメインが複数あります (後の定義は無視)'); continue; }
domById[dm.id] = dm; domByName[dm.name] = dm;
res.domains.push(dm);
}
for (ci = 0; ci < erd.children.length; ci++) {
var c = erd.children[ci];
if (c.tag !== 'ENTITY') continue;
var e = { id: c.attrs.ID, pname: c.attrs['P-NAME'] || ('E' + c.attrs.ID), lname: c.attrs['L-NAME'] || '', comment: c.attrs.COMMENT || '',
dependent: c.attrs.DEPENDENT === '1', attrs: [], pos: {}, bkColor: _oberColor(c.attrs.BRUSHCOLOR) }; // ★No.188: 背景色 (実物はビュー側の ENTITY が持つ → 下で補う)
for (var ai = 0; ai < c.children.length; ai++) {
var a = c.children[ai];
if (a.tag !== 'ATTR') continue;
var at = _oberTypeInto({ id: a.attrs.ID, pname: a.attrs['P-NAME'] || ('A' + a.attrs.ID), lname: a.attrs['L-NAME'] || '',
pk: a.attrs.PK === '1', notNull: a.attrs.NULL === '1', comment: a.attrs.COMMENT || '', fks: [], domain: '',
defVal: a.attrs.DEF || '' }, a.attrs); // ★No.229: 既定値 (DEF)
// ドメイン参照: A5M2 は属性に「型かドメインのどちらか」しか持てないので、 型欄は *ドメイン名 になり
// 属性固有の型・桁はドメインの型に置き換わる。 違うときは警告して知らせる (品目.品目ID 桁10 vs ドメイン 桁0 等)
var did = a.attrs.DDOMAINID || '0';
if (did !== '0' && domById[did]) {
at.domain = domById[did].name;
var tA = _a5erType(at), tD = _a5erType(domById[did]);
if (at.type && tA !== tD) {
res.warnings.push(e.pname + '.' + at.pname + ': 属性の型 ' + tA + ' はドメイン「' + at.domain + '」の型 ' + tD +
' に置き換わります (A5:SQL Mk-2 は型とドメインを併記できません)');
}
} else if (did !== '0') {
res.warnings.push(e.pname + '.' + at.pname + ': DDOMAINID=' + did + ' のドメイン定義が見つかりません (型で出力)');
}
for (var fi = 0; fi < a.children.length; fi++) {
if (a.children[fi].tag === 'FK') at.fks.push({ rel: a.children[fi].attrs.RELATION, parentAttr: a.children[fi].attrs.ATTR });
}
e.attrs.push(at);
attrById[at.id] = { ent: e, attr: at };
}
// ★No.229: ユニーク索引 (INDEX I-TYPE 1) と索引 (2)。 0 = 主キーは出さない。 COLUMN ID → 属性の物理名
e.indexes = [];
for (var ixi = 0; ixi < c.children.length; ixi++) {
var ix = c.children[ixi];
if (ix.tag !== 'INDEX' || String(ix.attrs['I-TYPE'] || '0') === '0') continue;
var ixCols = [];
for (var ixc = 0; ixc < ix.children.length; ixc++) {
if (ix.children[ixc].tag !== 'COLUMN') continue;
var ixa = attrById[ix.children[ixc].attrs.ID];
if (ixa && ixa.ent === e) ixCols.push(ixa.attr.pname);
}
if (ixCols.length) e.indexes.push({ name: ix.attrs['P-NAME'] || ix.attrs['L-NAME'] || ('IX' + ix.attrs.ID), unique: String(ix.attrs['I-TYPE']) === '1', cols: ixCols });
}
res.entities.push(e);
entById[e.id] = e;
}
res.shapes = []; res.lines = []; res.comments = []; // ★No.226: 図形・直線 (ビューの SHAPE / SHAPELINE)
res.nonDepDash = true; // ★No.230: OBER の IE 表示 = 非依存は破線 → A5M2 の UseNondependenceDashLine=1
for (ci = 0; ci < erd.children.length; ci++) {
var r0 = erd.children[ci];
if (r0.tag !== 'RELATION') continue;
var r = { id: r0.attrs.ID, pname: r0.attrs['P-NAME'] || '', parentId: r0.attrs['P-ENTITY'], childId: r0.attrs['C-ENTITY'],
rtype: r0.attrs['R-TYPE'] || '',
caption: (r0.attrs['VERBP-C'] || '') + ((r0.attrs['VERBC-P'] || '') ? ((r0.attrs['VERBP-C'] || '') ? ' / ' : '') + r0.attrs['VERBC-P'] : ''), // ★No.228: 親から子 / 子から親
card: r0.attrs.CARDINALITY || '0', cardC: r0.attrs.CARDINALITYC || '', // ★No.223
parentCols: [], childCols: [], fkPk: 0, fkNull: 0, pages: [],
optParent: r0.attrs.NULL === '0' }; // ★No.189 (実物で訂正 2026-09-28): RELATION の NULL は ATTR と同じ「NOT NULL」の旗 = 1 が親必須、 0 が親任意 (IDEF1X の親側 ◇)
relById[r.id] = r;
res.relations.push(r);
}
// ★No.186: サブタイプ (SUBTYPE: 親 P-ENTITY、 子 = C-ENTITY が指す RELATION の ID、 ATTR = 判別属性の ID、 S-TYPE = 種別) → A5M2 の [Subtype] ノード
// S-TYPE は 0 = 完全 (OBER の「確定」= 円と二重線)、 1 = 不完全 (実物でテスター確認 2026-09-28、 No.186 確認NG。 1.0.21 は逆に読んでいた)
var subDefs = [], subById = {};
for (ci = 0; ci < erd.children.length; ci++) {
var s0 = erd.children[ci];
if (s0.tag !== 'SUBTYPE') continue;
var sd = { id: s0.attrs.ID, parentId: s0.attrs['P-ENTITY'], stype: s0.attrs['S-TYPE'] || '', attrId: s0.attrs.ATTR || '0', relIds: [], pos: {} };
for (var sci = 0; sci < s0.children.length; sci++) if (s0.children[sci].tag === 'C-ENTITY') sd.relIds.push(s0.children[sci].attrs.ID);
subDefs.push(sd); subById[sd.id] = sd;
}
// FK: 子属性 → 親属性 (属性 ID) を関連ごとに集める
for (var ei = 0; ei < res.entities.length; ei++) {
var ent = res.entities[ei];
for (var xi = 0; xi < ent.attrs.length; xi++) {
var ax = ent.attrs[xi];
for (var fk = 0; fk < ax.fks.length; fk++) {
var rr = relById[ax.fks[fk].rel], pa = attrById[ax.fks[fk].parentAttr];
if (!rr || !pa) { res.warnings.push(ent.pname + '.' + ax.pname + ': FK の参照先が見つかりません'); continue; }
rr.childCols.push(ax.pname);
rr.parentCols.push(pa.attr.pname);
if (ax.pk) rr.fkPk++;
if (!ax.notNull) rr.fkNull++;
}
}
}
// ★No.187 (2026-10-01 確定 — テスター提供の同じモデルの IDEF1X 保存 / IE 保存の 2 ファイルは MODELVIEW の LERDTYPE だけが 0 / 1 で違う):
// 表記 = MODELVIEW の LERDTYPE (論理ビュー MODELTYPE 0) / PERDTYPE (物理 1) / BERDTYPE (2) で **0 = IDEF1X (OBER の既定)、 1 = IE**。
// 1.0.13〜1.0.22 の「1 = IDEF1X」は逆だった。 RELATION の SHOWTYPE は表記ではない (保存し直しても変わらない)。 ERD の ACTIVE-VIEW
// (無ければ最初のビュー) の表記を a5er の ViewFormat にする。 ビューが無ければ OBER の既定 = IDEF1X。
var activeView = erd.attrs ? (erd.attrs['ACTIVE-VIEW'] || '') : '', notation = null, firstNotation = null;
// ビュー = ページ (座標)
for (ci = 0; ci < erd.children.length; ci++) {
var mv = erd.children[ci];
if (mv.tag !== 'MODELVIEW') continue;
var pg = { name: mv.attrs['L-NAME'] || ('View' + (res.pages.length + 1)), entities: 0, relations: 0 };
var mtype = String(mv.attrs.MODELTYPE || '0'), ntv = mtype === '1' ? mv.attrs.PERDTYPE : (mtype === '2' ? mv.attrs.BERDTYPE : mv.attrs.LERDTYPE);
ntv = (ntv == null) ? '0' : String(ntv);
if (firstNotation == null) firstNotation = ntv;
if (activeView && (mv.attrs['L-NAME'] || '') === activeView) notation = ntv;
for (var vi = 0; vi < mv.children.length; vi++) {
var v = mv.children[vi];
if (v.tag === 'ENTITY') {
var ve = entById[v.attrs.ID];
if (!ve) continue;
var L0 = parseInt(v.attrs.LEFT, 10) || 0, T0 = parseInt(v.attrs.TOP, 10) || 0;
var R0 = parseInt(v.attrs.RIGHT, 10) || (L0 + 120), B0 = parseInt(v.attrs.BOTTOM, 10) || (T0 + 100);
ve.pos[pg.name] = { x: L0, y: T0, w: Math.max(40, R0 - L0), h: Math.max(30, B0 - T0) };
if (!ve.bkColor) ve.bkColor = _oberColor(v.attrs.BRUSHCOLOR); // ★No.188: 背景色はビューの ENTITY (負数 = システム色 = 白)。 最初に色のあるビューを採る
pg.entities++;
} else if (v.tag === 'RELATION') {
var vr = relById[v.attrs.ID];
if (vr) {
vr.pages.push(pg.name); pg.relations++;
// ★No.227: 線の経路 (POS の列: 両端 = 端子、 間 = 折れ点、 OBER の px)。 書き出し側が A5M2 の自由結線 (ラインモード 10) にする
var rps = [], rpi;
for (rpi = 0; rpi < v.children.length; rpi++) if (v.children[rpi].tag === 'POS') rps.push({ x: parseInt(v.children[rpi].attrs.LEFT, 10) || 0, y: parseInt(v.children[rpi].attrs.TOP, 10) || 0 });
if (rps.length >= 2) { if (!vr.routes) vr.routes = {}; vr.routes[pg.name] = { pts: rps, pa: v.attrs['P-ANCHOR'], ca: v.attrs['C-ANCHOR'] }; } // ANCHOR: 0 = 左 / 1 = 上 / 2 = 右 / 3 = 下
}
} else if (v.tag === 'SUBTYPE') { // ★No.186: サブタイプ記号の座標 (OBER は小さな箱。 中心を合わせて A5M2 の記号 72×50 (0.1 mm) の大きさに)
var vs = subById[v.attrs.ID];
if (vs) {
var SL = parseInt(v.attrs.LEFT, 10) || 0, ST = parseInt(v.attrs.TOP, 10) || 0;
var SR = parseInt(v.attrs.RIGHT, 10) || (SL + 24), SB = parseInt(v.attrs.BOTTOM, 10) || (ST + 24), SW = 72 / _OBER_PX, SH = 50 / _OBER_PX;
vs.pos[pg.name] = { x: (SL + SR) / 2 - SW / 2, y: (ST + SB) / 2 - SH / 2, w: SW, h: SH };
}
} else if (v.tag === 'SRELATION') { // 記号の線 (親→記号 / 記号→子)。 ページの線の数に数える (座標は書き出し側が記号と箱から作る)
if (subById[v.attrs['P-ENTITY']] || subById[v.attrs['C-ENTITY']]) pg.relations++;
} else if (v.tag === 'SHAPE') { // ★No.226: 図形 (SHAPETYPE 0 四角形 / 1 角丸 / 2 楕円 / 3 テキスト) → [Shape]。 テキストは線無し (LineType=1) の矩形 + Text
var hL = parseInt(v.attrs.LEFT, 10) || 0, hT = parseInt(v.attrs.TOP, 10) || 0, hR = parseInt(v.attrs.RIGHT, 10) || hL, hB = parseInt(v.attrs.BOTTOM, 10) || hT;
var stp = String(v.attrs.SHAPETYPE || '0');
res.shapes.push({ page: pg.name, x: hL, y: hT, w: Math.max(1, hR - hL), h: Math.max(1, hB - hT),
shapeType: stp === '1' ? 'RoundRect' : stp === '2' ? 'Ellipse' : 'Rectangle', // ★No.247: 角丸四角形は RoundRect (Round は円)
text: String(v.attrs.VALUE || '').replace(/[\r\n]+$/, ''),
lineType: stp === '3' ? 1 : (String(v.attrs.PENSTYLE || '0') !== '0' ? 2 : 0),
lineColor: _oberColor(v.attrs.PENCOLOR), brushColor: stp === '3' ? '' : _oberColor(v.attrs.BRUSHCOLOR),
brushAlpha: stp === '3' ? 0 : null, // ★No.250: テキストは背景が無く下の図形が透ける (BrushColor 無しだと A5M2 も描画器も白で塗る)
lineWidth: parseInt(v.attrs.PENWIDTH, 10) || 1, fontSize: parseFloat(v.attrs.FONTSIZE) || 0,
fontBold: v.attrs.FONTBL === '1', fontColor: _oberColor(v.attrs.FONTCOLOR),
z: (pg._z = (pg._z || 0) + 1) }); // ★No.248: 重なり順 = ビュー内の出現順 (後が手前) → A5M2 の ZOrder
} else if (v.tag === 'SHAPELINE') { // ★No.226: 直線 (POS の列) → 区間ごとの [Line]。 S-STYLE / E-STYLE 1 = 矢印 (▶)
var lps = [], lpi, lz = (pg._z = (pg._z || 0) + 1); // ★No.248: 直線 1 本 (区間は同じ順位) の重なり順
for (lpi = 0; lpi < v.children.length; lpi++) if (v.children[lpi].tag === 'POS') lps.push({ x: parseInt(v.children[lpi].attrs.LEFT, 10) || 0, y: parseInt(v.children[lpi].attrs.TOP, 10) || 0 });
for (lpi = 0; lpi + 1 < lps.length; lpi++) {
res.lines.push({ page: pg.name, x: lps[lpi].x, y: lps[lpi].y, w: lps[lpi + 1].x - lps[lpi].x, h: lps[lpi + 1].y - lps[lpi].y,
lineColor: _oberColor(v.attrs.PENCOLOR), lineWidth: parseInt(v.attrs.PENWIDTH, 10) || 1,
lineType: String(v.attrs.PENSTYLE || '0') !== '0' ? 2 : 0,
startTerm: (lpi === 0 && String(v.attrs['S-STYLE'] || '0') !== '0') ? 4 : 0,
endTerm: (lpi + 2 === lps.length && String(v.attrs['E-STYLE'] || '0') !== '0') ? 4 : 0, z: lz });
}
}
}
res.pages.push(pg);
}
res.viewFormat = ((notation != null ? notation : firstNotation) === '1') ? '0' : '1'; // 0=IE / 1=IDEF1X (No.187)
// 関連の確定: 親子の実在、 依存 (FK 属性が PK) / 親側の任意 (FK 属性に NULL 可があるか)
var kept = [];
for (var ki = 0; ki < res.relations.length; ki++) {
var kr = res.relations[ki], pe = entById[kr.parentId], ce = entById[kr.childId];
if (!pe || !ce) { res.warnings.push('RELATION ' + kr.pname + ': 親または子のエンティティが見つかりません (省略)'); continue; }
kr.parent = pe.pname; kr.child = ce.pname;
// 依存 (識別) = OBER の R-TYPE (0 = 依存、 1 = 非依存) を尊重し、 無ければ FK 属性が主キーかで判定 (実物 2026-09-28: 非依存なのに FK が主キーの関連があり、 図は破線)
kr.dep = kr.rtype === '0' ? true : (kr.rtype === '1' || kr.rtype === '2') ? false : (kr.fkPk > 0);
kr.rt1 = (kr.optParent || (kr.childCols.length && kr.fkNull > 0)) ? '1' : '2'; // 親側: 関連の NULL=1 か FK に NULL 可 → 0または1、 それ以外 → 1 (No.189)
// ★No.223 (テスター提供の ERパターン網羅 で確認 2026-10-01): CARDINALITY 0 = 0以上 / 1 = 1以上 / 2 = 0または1 / 3 = 定数 (個数 = CARDINALITYC)
// → A5M2 の RelationType2 3 / 4 / 1 / 5 (+ Cardinarity2)
kr.rt2 = kr.card === '1' ? '4' : kr.card === '2' ? '1' : kr.card === '3' ? '5' : '3';
if (kr.rt2 === '5') kr.card2 = kr.cardC || '';
// ★No.224: R-TYPE 2 = 多対多 (両端が鳥足、 FK 属性は無い) → 親側も「多」(RelationType1=3)。 FK 無しの警告は出さない
if (kr.rtype === '2') kr.rt1 = '3';
if (!kr.childCols.length && kr.rtype !== '2') res.warnings.push('RELATION ' + kr.pname + ' (' + pe.lname + ' → ' + ce.lname + '): FK 属性がありません');
kept.push(kr);
}
// ★No.186: サブタイプの子の関連 (C-ENTITY が指す RELATION) を [Subtype] ノードにまとめる (親→記号→各サブタイプの関連は書き出し側 _a5erWriteModel が作る)
var consumed = {}, subNames = {};
for (var sdi = 0; sdi < subDefs.length; sdi++) {
var sdf = subDefs[sdi], spe = entById[sdf.parentId];
if (!spe) { res.warnings.push('SUBTYPE ' + sdf.id + ': 親エンティティが見つかりません (省略)'); continue; }
var snm = 'SUBTYPE_' + spe.pname;
if (subNames[snm]) snm += '_' + sdf.id;
subNames[snm] = true;
var node = { pname: snm, parent: spe.pname, complete: sdf.stype !== '1', shared: false,
caption: (sdf.attrId !== '0' && attrById[sdf.attrId]) ? attrById[sdf.attrId].attr.lname : '', pos: sdf.pos, subs: [] };
for (var sri = 0; sri < sdf.relIds.length; sri++) {
var srel = relById[sdf.relIds[sri]];
if (!srel || !srel.parent || srel.parentId !== sdf.parentId) { res.warnings.push('SUBTYPE ' + spe.lname + ': 子の関連 (ID ' + sdf.relIds[sri] + ') が見つかりません'); continue; }
node.subs.push({ child: srel.child, parentCols: srel.parentCols, childCols: srel.childCols, pages: srel.pages });
consumed[srel.id] = true;
}
if (node.subs.length) res.subtypes.push(node);
}
if (res.subtypes.length) { var kept2 = []; for (ki = 0; ki < kept.length; ki++) if (!consumed[kept[ki].id]) kept2.push(kept[ki]); kept = kept2; }
res.relations = kept;
res.stats.tables = res.entities.length;
for (var si = 0; si < res.entities.length; si++) res.stats.columns += res.entities[si].attrs.length;
res.stats.fks = res.relations.length;
for (si = 0; si < res.subtypes.length; si++) res.stats.fks += 1 + res.subtypes[si].subs.length; // 親→記号 + 記号→各サブタイプ = .a5er の [Relation] 数
res.stats.subtypes = res.subtypes.length;
res.stats.pages = res.pages.length;
res.stats.domains = res.domains.length;
return res;
}
// 変換モデル (ページ・座標つき) → .a5er。 ビューに無いエンティティは「(未配置)」ページに格子で置く
// ============================================================
// Visio (.vsdx、 T字形 / PRIDE の ER 図) → 変換モデル (Ver1.0.6)
// ・エンティティ = 3 つの子図形 [属性ブロック][識別子 (PK)][名前] を持つグループ (XML の並びもこの順。 子が 3 つで文字を持つもの)。
// ・属性の無い参照エンティティ (他図で定義、 名前だけの図形) = 線がつながる 1 行の単独図形。 属性は無く、 FK 名から主キーを補う。
// ・リレーション = T字形の規約 (FK 識別子名 = 親エンティティ名。 末尾の C / # を剥がした core で 完全一致 → 接尾 → 接頭 → 親の PK 名) +
// コネクタ (1-D 図形) と <Connects> (両端の図形) で照合。 線があるのに FK が無い組は警告に残す。 サブタイプ記号につながる線は変換しない。
// ・データ項目記号: 末尾 C = コード / # = 番号 / (FK) 外部キー / (AK) 代替キー。 列末尾の「|ドメイン名」は A5M2 のドメイン (= 業務データ辞書名)。
// ・座標: Visio はインチ・左下原点 → A5 の 0.1 mm 単位・左上原点。 エンティティの背景色 (FillForegnd) は BkColor に写す。
// ・★Ver1.0.22 (No.212 / 222) Visio 標準の「データベース表記」ステンシル (クロウフット / IDEF1X、 Visio Plan 2 の Database 図形) も読む:
// マスターの User.msvShapeCategories (DbEntity / DbAttribute / DbPkSeparator / DbRelationship) で見分け (_vsdxStdMasters)、 エンティティ = User.EntityName、
// 属性 = 独立した図形 (User.AttributeName / ItemIndex、 入っているエンティティは座標で決める、 主キー = Primary Key Attribute のマスター、 外部キー = User.ForeignKey か
// 名前の (FK))、 型 = IDEF1X の User.AttributeType / クロウフットの型欄の子図形 (インスタンスが上書きした値。 エンティティが型を表示しているときは既定の int も)、
// 図形データ (Prop) の「コメント」「型」行、 校閲のコメント (visio/comments.xml) = エンティティ / 属性のコメント。 関係 = Relationship 図形の Connects と
// 端記号 (BeginArrow / EndArrow: 29 = 0以上, 28 = 1以上, 25 = 1つのみ, 30 = 0または1 / IDEF1X 42 = ●, 22 = ◇) → RelationType と向き (「多」の側が子、
// 1 対 1 は FK を持つ側が子、 どちらも多 = 多対多で列なし)。 FK 列は子の (FK) 属性と親の主キーの同名、 無ければ未使用の (FK) 列を順に。 T字形の規約とは独立。
// ・ZIP の展開 (_vsdxUnzip) はブラウザ (DecompressionStream) と Node で動く。 サーバ (Nashorn) では定義だけで呼ばれない。
// ============================================================
function _vsdxAttr(tag, name) {
var re = new RegExp('\\s' + name + "\\s*=\\s*(?:'([^']*)'|\"([^\"]*)\")");
var m = re.exec(tag);
return m ? _xmlUnesc(m[1] != null ? m[1] : m[2]) : null;
}
function _vsdxCells(body) {
var out = {}, re = /<Cell\b([^>]*?)\/?>/g, m;
while ((m = re.exec(body))) {
var n = _vsdxAttr(m[1], 'N'), v = _vsdxAttr(m[1], 'V');
if (n && v != null && !out.hasOwnProperty(n)) out[n] = v;
}
return out;
}
function _vsdxText(body) {
var m = /<Text>([\s\S]*?)<\/Text>/.exec(body);
if (!m) return '';
return _xmlUnesc(m[1].replace(/<[^>]*>/g, '')).replace(/\r\n?/g, '\n');
}
function _vsdxShapes(xml) {
// ★Ver1.0.22 (No.210): 入れ子のグループも木のまま読む (子は任意の深さ)。 図形 = { id, type, master, masterShape, cells, text, children }
// グループの cells / text は最初の子図形の手前まで (子の Text を親に取り込まない)
var s = String(xml || ''), re = /<Shape\b[^>]*>|<\/Shape>|<Shapes>|<\/Shapes>/g, m, stack = [], tops = [];
function attach(sh) { if (stack.length) stack[stack.length - 1].children.push(sh); else tops.push(sh); }
while ((m = re.exec(s))) {
var tok = m[0];
if (tok === '<Shapes>' || tok === '</Shapes>') continue;
if (tok === '</Shape>') {
var done = stack.pop();
if (!done) continue;
var body = s.substring(done.start, done.bodyEnd != null ? done.bodyEnd : m.index);
done.cells = _vsdxCells(body); done.text = _vsdxText(body);
var gmo = /<Section N='Geometry'[^>]*>([\s\S]*?)<\/Section>/.exec(body); // ★No.253: 図形の種類 (Ellipse / MoveTo + LineTo)
done.geo = gmo ? (gmo[1].match(/<Row T='[A-Za-z]+'/g) || []).map(function (t) { return t.replace(/^<Row T='|'$/g, ''); }) : [];
done.geoPts = []; // ★No.256: 行ごとの X / Y (関係図形の線の経路。 無いセルは null、 空要素の行は無視)
if (gmo) { var rowRe2 = /<Row T='([A-Za-z]+)'[^>\/]*>([\s\S]*?)<\/Row>/g, rw2; while ((rw2 = rowRe2.exec(gmo[1]))) { var rc2 = _vsdxCells(rw2[2]); done.geoPts.push({ t: rw2[1], x: rc2.X != null ? parseFloat(rc2.X) : null, y: rc2.Y != null ? parseFloat(rc2.Y) : null }); } }
var ux = _vsdxUser(body), uk; // ★No.212 / 222: User 行 (標準ステンシルの名前・順序・キー) と図形データ。 userOwn = インスタンス自身が持つ行 (継承前)
done.user = ux.user; done.prop = ux.prop; done.userOwn = {};
for (uk in ux.user) if (ux.user.hasOwnProperty(uk)) done.userOwn[uk] = 1;
done.hasText = body.indexOf('<Text>') >= 0 || body.indexOf('<Text/>') >= 0 || body.indexOf('<Text ') >= 0; // Text 要素の有無 (空でも「上書き」)
delete done.start; delete done.bodyEnd;
attach(done);
continue;
}
var sh = { id: _vsdxAttr(tok, 'ID'), type: _vsdxAttr(tok, 'Type') || '', master: _vsdxAttr(tok, 'Master'), masterShape: _vsdxAttr(tok, 'MasterShape'),
start: m.index + tok.length, bodyEnd: null, cells: {}, text: '', user: {}, userOwn: {}, prop: [], children: [] };
if (/\/>$/.test(tok)) { delete sh.start; delete sh.bodyEnd; attach(sh); continue; } // 空要素
if (stack.length && stack[stack.length - 1].bodyEnd == null) stack[stack.length - 1].bodyEnd = m.index;
stack.push(sh);
}
return tops;
}
// ★Ver1.0.22 (No.209): ステンシルのマスターから継承する。 インスタンスは上書きした値だけを持つ (座標の無い子図形、 無い子図形は
// マスターのまま) ので、 無い cells / text / 子図形をマスターの先頭図形 (木) から補う。 子は MasterShape (マスター側の ID) で対応づける
function _vsdxInherit(sh, masters, deep) {
if (!sh.master || !masters || !masters[sh.master]) return;
// ★No.212 / 222: インスタンスの子の MasterShape はマスターの入れ子の中の図形を直接指すことがある (クロウフットの属性: 型欄 6 はマスターでは
// グループ 12 の中) → deep (標準ステンシルの図形) のときだけマスターの図形を深さに関わらず ID で引き、 当たった図形とその祖先は複製しない。
// T字形 / PRIDE (deep 無し) は従来どおり同じ階層だけ (実物 DM_イベント の結果を変えない)
var index = {}, seen = {};
function walk(n, parent) { var i; index[n.id] = { node: n, parent: parent }; for (i = 0; i < n.children.length; i++) walk(n.children[i], n); }
walk(masters[sh.master], null);
function clone(src, prefix) {
var c = { id: prefix + src.id, type: src.type, masterShape: src.id, cells: {}, text: src.text, user: {}, userOwn: {}, prop: (src.prop || []).slice(0), children: [] }, k, i;
for (k in src.cells) if (src.cells.hasOwnProperty(k)) c.cells[k] = src.cells[k];
for (k in src.user) if (src.user.hasOwnProperty(k)) c.user[k] = src.user[k];
for (i = 0; i < src.children.length; i++) c.children.push(clone(src.children[i], prefix));
return c;
}
function fill(dst, src) {
var k, i, j;
for (k in src.cells) if (src.cells.hasOwnProperty(k) && dst.cells[k] == null) dst.cells[k] = src.cells[k];
if (!dst.user) dst.user = {};
if (!dst.prop || !dst.prop.length) dst.prop = (src.prop || []).slice(0);
for (k in src.user) if (src.user.hasOwnProperty(k) && dst.user[k] == null) dst.user[k] = src.user[k];
if (!String(dst.text || '').replace(/[\s\u3000]/g, '') && !dst.hasText && src.text) dst.text = src.text; // Text 要素が無いときだけ (空の Text = 上書きで消している。 DM 実物のサブタイプ記号は空)
for (i = 0; i < dst.children.length; i++) {
var ms = dst.children[i].masterShape, hit = null, p;
if (ms == null) continue;
for (j = 0; j < src.children.length && !hit; j++) if (src.children[j].id === ms) hit = index[ms];
if (!hit && deep && index[ms]) hit = index[ms];
if (!hit) continue;
fill(dst.children[i], hit.node);
for (p = hit; p; p = p.parent ? index[p.parent.id] : null) seen[p.node.id] = 1;
}
for (j = 0; j < src.children.length; j++) if (!seen[src.children[j].id]) dst.children.push(clone(src.children[j], 'm' + sh.master + '_'));
}
fill(sh, masters[sh.master]);
}
// ★Ver1.0.22 (No.210): 入れ子のグループを展開して「エンティティ / 線 / 名前だけの図形」の一覧にする。 グループの子はグループのローカル座標
// (原点 = Pin − LocPin) なので、 展開した図形の PinX / PinY はページ座標に直す (エンティティの 3 子は役割の並びにしか使わないのでそのまま)
function _vsdxFlatten(tops, masters, stdOf) { // stdOf(図形) = 標準ステンシルの役割 (No.212 / 222: その図形はそのまま一覧に載せ、 T字形の判定をしない)
var out = [];
function num(v, d) { var n = parseFloat(v); return isNaN(n) ? d : n; }
function visit(sh, ox, oy, nested) {
_vsdxInherit(sh, masters, !!(stdOf && stdOf(sh)));
if (nested) {
var c = {}, k;
for (k in sh.cells) if (sh.cells.hasOwnProperty(k)) c[k] = sh.cells[k];
if (c.PinX != null) c.PinX = String(num(c.PinX, 0) + ox);
if (c.PinY != null) c.PinY = String(num(c.PinY, 0) + oy);
sh.cells = c;
}
var isConn = sh.cells.BeginX != null && sh.cells.EndX != null;
if ((stdOf && stdOf(sh)) || isConn || !sh.children.length || _vsdxEntity(sh)) { out.push(sh); return; }
// 子が葉だけのグループ (凡例の記号、 文字の無い 3 子図形など) は従来どおり 1 つの図形として扱う (エンティティでなければ無視)。
// 展開するのは子にグループや線を含む「入れ子の容器」だけ (DM 実物で凡例の子図形が名前だけの参照エンティティ「識別子」になった)
var hasContainer = false, ci2;
for (ci2 = 0; ci2 < sh.children.length; ci2++) {
var ch2 = sh.children[ci2];
if (ch2.children.length || (ch2.cells.BeginX != null && ch2.cells.EndX != null)) { hasContainer = true; break; }
}
if (!hasContainer) { out.push(sh); return; }
var w = num(sh.cells.Width, 0), h = num(sh.cells.Height, 0);
var lx = sh.cells.LocPinX != null ? num(sh.cells.LocPinX, w / 2) : w / 2, ly = sh.cells.LocPinY != null ? num(sh.cells.LocPinY, h / 2) : h / 2;
var gx = num(sh.cells.PinX, 0) - lx, gy = num(sh.cells.PinY, 0) - ly, i;
for (i = 0; i < sh.children.length; i++) visit(sh.children[i], gx, gy, true);
}
var t;
for (t = 0; t < tops.length; t++) visit(tops[t], 0, 0, false);
return out;
}
function _vsdxUser(body) {
// ★Ver1.0.22 (No.212 / 222): シェイプシートの User セクション (標準ステンシルの EntityName / AttributeName / ItemIndex / PrimaryKey …) と
// 図形データ (Prop セクション: Label / Value) を読む。 戻り = { user: {行名: Value}, prop: [{ name, label, value }] }
var out = { user: {}, prop: [] }, s = String(body || ''), secRe = /<Section\b([^>]*)>([\s\S]*?)<\/Section>/g, m;
while ((m = secRe.exec(s))) {
var sn = _vsdxAttr(m[1], 'N');
if (sn !== 'User' && sn !== 'Prop' && sn !== 'Property') continue; // ★No.254: 図形データは Section N='Property' (Visio 2013+ の .vsdx。 Prop は旧形)
var rowRe = /<Row\b([^>]*)>([\s\S]*?)<\/Row>/g, r;
while ((r = rowRe.exec(m[2]))) {
var rn = _vsdxAttr(r[1], 'N'), cells = _vsdxCells(r[2]);
if (!rn) continue;
if (sn === 'User') { if (cells.Value != null && !out.user.hasOwnProperty(rn)) out.user[rn] = cells.Value; }
else out.prop.push({ name: rn, label: cells.Label || rn, value: cells.Value || '' });
}
}
return out;
}
function _vsdxStdMasters(masters) {
// ★Ver1.0.22 (No.212 / 222): Visio 標準の「データベース表記」ステンシル (クロウフット / IDEF1X) のマスターを種類分けする。
// 種類はマスターの先頭図形の User.msvShapeCategories (Database;DbEntity / DbAttribute;DbListItem / DbPkSeparator / DbRelationship) で見る
// (NameU は言語や利用者の改名で変わる。 T字形の自作マスターは持たない)。
// 戻り = { any: 1 つでもあるか, role: {マスター ID: 'ent' | 'attr' | 'sep' | 'rel'}, pk: {ID: 1 = 主キー属性のマスター},
// typeSlot: {ID: 型欄の子図形の ID (マスター側、 任意の深さ。 既定の文字 int)}, idef: IDEF1X か (端記号 42 / 22、 属性の AttributeType / OptionalAttr) }
var out = { any: false, role: {}, pk: {}, typeSlot: {}, idef: false }, mk;
function findType(n) { var i, r; if (n.text && /^int$/i.test(String(n.text).replace(/[\s\u3000]/g, ''))) return n.id; for (i = 0; i < n.children.length; i++) { r = findType(n.children[i]); if (r) return r; } return null; }
for (mk in masters) if (masters.hasOwnProperty(mk)) {
var top = masters[mk], u = top.user || {}, cat = String(u.msvShapeCategories || '');
if (!/\bDb(Entity|Attribute|PkSeparator|Relationship)\b/.test(cat)) continue;
out.any = true;
if (/\bDbEntity\b/.test(cat)) out.role[mk] = 'ent';
else if (/\bDbPkSeparator\b/.test(cat)) out.role[mk] = 'sep';
else if (/\bDbRelationship\b/.test(cat)) {
out.role[mk] = 'rel';
if (/^(42|22)$/.test(String(top.cells.BeginArrow || '')) || /^(42|22)$/.test(String(top.cells.EndArrow || ''))) out.idef = true;
} else {
out.role[mk] = 'attr';
if (String(u.PrimaryKey) === '1') out.pk[mk] = 1;
if (u.AttributeType != null || u.OptionalAttr != null) out.idef = true;
var ts = null, i;
for (i = 0; i < top.children.length && !ts; i++) ts = findType(top.children[i]);
if (ts) out.typeSlot[mk] = ts;
}
}
return out;
}
function _vsdxComments(xml) {
// ★Ver1.0.22 (No.212 / 222): visio/comments.xml (校閲のコメント) → [{ page: ページ ID, shape: 図形 ID, text }]。 図形に付いていないコメント (ShapeID 無し) は捨てる
var out = [], s = String(xml || ''), re = /<CommentEntry\b([^>]*?)(?:\/>|>([\s\S]*?)<\/CommentEntry>)/g, m;
while ((m = re.exec(s))) {
var pg = _vsdxAttr(m[1], 'PageID'), sh = _vsdxAttr(m[1], 'ShapeID');
if (pg == null || sh == null) continue;
var txt = _xmlUnesc(String(m[2] || '').replace(/<[^>]*>/g, '')).replace(/\r\n?/g, '\n').replace(/[\s\u3000]+$/, '');
if (txt) out.push({ page: pg, shape: sh, text: txt });
}
return out;
}
function _vsdxConnects(xml) {
var out = {}, re = /<Connect\b([^>]*?)\/?>/g, m;
while ((m = re.exec(xml))) {
var from = _vsdxAttr(m[1], 'FromSheet'), cell = _vsdxAttr(m[1], 'FromCell') || '', to = _vsdxAttr(m[1], 'ToSheet');
if (!from || !to) continue;
if (!out[from]) out[from] = {};
if (/^BeginX$/i.test(cell)) out[from].begin = to; else if (/^EndX$/i.test(cell)) out[from].end = to;
}
return out;
}
function _vsdxOpenParen(t) {
var o = 0, i, c;
for (i = 0; i < t.length; i++) { c = t.charAt(i); if (c === '(' || c === '(') o++; else if (c === ')' || c === ')') o--; }
return o > 0;
}
function _vsdxLines(text) {
var raw = String(text || '').split('\n'), out = [], i;
for (i = 0; i < raw.length; i++) {
var ln = raw[i].replace(/[\s\u3000]+$/, ''), cont = /^[\u3000 ]/.test(ln);
ln = ln.replace(/^[\s\u3000]+/, '');
if (!ln || /^[・・.。\s\u3000]+$/.test(ln) || /^[((]属性不明[))]$/.test(ln)) continue;
var prev = out.length ? out[out.length - 1] : null;
if (prev != null && (cont || /[++((]$/.test(prev) || _vsdxOpenParen(prev))) out[out.length - 1] = prev + ln;
else out.push(ln);
}
return out;
}
function _vsdxCore(t) {
t = String(t || '');
while (t.length && /[#C]$/.test(t)) t = t.substring(0, t.length - 1);
return t;
}
function _vsdxCol(line, pk) {
var dom = ''; // Ver1.0.11: 「列名|辞書名」の規約は廃止 (データドメインは辞書側の EDM 属性宣言で結ぶ)
// ★No.214: T字形 (TM) の「(R)」(他のエンティティから持ち込んだ個体指定子 = 参照) も外部キー
var fk = /[((]\s*(FK|FK|R|R)\s*[))]/i.test(line), ak = /[((]\s*(AK|AK)\s*[))]/i.test(line);
var base = line.replace(/[((]\s*(FK|AK|FK|AK|R|R)\s*[))]/gi, '').replace(/[\s\u3000]+$/, '').replace(/^[\s\u3000]+/, '');
return { lname: base, pname: base, type: '', len: '', prec: '', scale: '', domain: dom, pk: !!pk, fk: fk, ak: ak, notNull: !!pk,
comment: fk ? 'FK' : (ak ? 'AK' : '') };
}
function _vsdxColor(c) {
var m = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(String(c || ''));
return m ? ('$' + (m[3] + m[2] + m[1]).toUpperCase()) : '$FFFFFF';
}
function _vsdxBox(cells, pageH) {
var IN = 254; // 1 inch = 25.4 mm = 254 (0.1 mm 単位)
var px = parseFloat(cells.PinX) || 0, py = parseFloat(cells.PinY) || 0, w = parseFloat(cells.Width) || 0, h = parseFloat(cells.Height) || 0;
var lx = cells.LocPinX != null ? parseFloat(cells.LocPinX) : w / 2, ly = cells.LocPinY != null ? parseFloat(cells.LocPinY) : h / 2;
var left = px - lx, bottom = py - ly;
return { x: Math.round(left * IN), y: Math.round((pageH - bottom - h) * IN), w: Math.round(w * IN), h: Math.round(h * IN) };
}
function _vsdxConnRoute(sh, pageH) {
// ★No.256: 関係図形 (1-D) の線の経路。 Geometry の X / Y は図形の箱の中の座標 (Begin を起点、 最後の点 = End - Begin)。 まっすぐな線は箱が端記号の幅
// (≈ 0.197 in) しか無く MoveTo (0.098, 0) のように中央を通る → 細い軸だけ半分を引く。 折れ線は箱が広く MoveTo を持たない (マスターから継承した (0,0) = Begin)
// (実物: 出庫 = Begin → 右 0.245 → 上 → 左 → End、 顧客→顧客与信 = ページの左端を回る)。 角の丸み (ArcTo) は終点への直線で近似。
// 戻り = ページ座標 (0.1 mm、 y は上が原点) の点の列。 Begin が無い / 曲線 (NURBS 等) を含むなら null (= 自動)
var c = sh.cells || {}, pts = sh.geoPts || [], IN = 254, out = [], i;
if (c.BeginX == null || c.BeginY == null || pts.length < 1 || (pts.length < 2 && pts[0].t === 'MoveTo')) return null;
var bx = parseFloat(c.BeginX) || 0, by = parseFloat(c.BeginY) || 0, w = Math.abs(parseFloat(c.Width) || 0), h = Math.abs(parseFloat(c.Height) || 0);
// ★細い方の軸 = 端記号の幅 (≈ 0.197 in) のときだけ中央 (半分) を引く。 折れ線の関係図形は箱が広く、 (0,0) = Begin (実物: 出庫 = 右へ 0.245 → 上へ → 左へ → End に一致)
var offX = (w > 0 && w < 0.3) ? w / 2 : 0, offY = (h > 0 && h < 0.3) ? h / 2 : 0;
if (pts[0].t !== 'MoveTo') pts = [{ t: 'MoveTo', x: 0, y: 0 }].concat(pts); // マスターから継承した MoveTo (0,0) は図形側に無い
for (i = 0; i < pts.length; i++) {
if (pts[i].t !== 'MoveTo' && pts[i].t !== 'LineTo' && pts[i].t !== 'ArcTo' && pts[i].t !== 'EllipticalArcTo') return null; // 角の丸み (ArcTo) は終点への直線で近似
var lx = pts[i].x == null ? 0 : pts[i].x, ly = pts[i].y == null ? 0 : pts[i].y;
out.push({ x: Math.round((bx + lx - offX) * IN), y: Math.round((pageH - (by + ly - offY)) * IN) });
}
return out;
}
function _vsdxEntity(g) {
if (!g.children || g.children.length !== 3) return null;
var ch = g.children.slice(0), withText = 0, i;
for (i = 0; i < 3; i++) if (ch[i].text.replace(/[\s\u3000]/g, '')) withText++;
if (withText < 2) return null;
// 役割は位置で決める (XML の並びは図形ごとに違う): PinY が高い順に [名前][識別子][属性]。 属性ブロックは PinY を持たない (一番下) ことが多い
function py(c) { return c.cells.PinY != null ? parseFloat(c.cells.PinY) : -1e9; }
function px(c) { return c.cells.PinX != null ? parseFloat(c.cells.PinX) : 0; }
ch.sort(function (a, b) { return py(b) - py(a); });
var nameBox = ch[0], pkBox = ch[1], attrBox = ch[2];
// ★No.214: T字形本来の形 (名前の下に 左 = 個体指定子、 右 = 性質) = 2 番目と 3 番目の PinY がほぼ同じ → 左 (PinX 小) が識別子、 右が属性
if (py(ch[1]) > -1e8 && Math.abs(py(ch[1]) - py(ch[2])) < 0.05) {
if (px(ch[1]) <= px(ch[2])) { pkBox = ch[1]; attrBox = ch[2]; } else { pkBox = ch[2]; attrBox = ch[1]; }
}
var name = _vsdxLines(nameBox.text).join('').replace(/[\s\u3000]+/g, '');
if (!name || /^【/.test(name) || /^(エンティティ名|エンティティ名)$/.test(name)) return null;
return { name: name, attrLines: _vsdxLines(attrBox.text), pkLines: _vsdxLines(pkBox.text), color: nameBox.cells.FillForegnd || attrBox.cells.FillForegnd || '' };
}
function _vsdxAddCols(ent, lines, pk) {
var i;
for (i = 0; i < lines.length; i++) {
var c = _vsdxCol(lines[i], pk);
if (!c.lname || ent._keys[c.lname]) continue;
ent._keys[c.lname] = 1;
ent.attrs.push(c);
}
}
function _vsdxParse(bundle) {
var res = { kind: 'vsdx', name: bundle.name || '', pages: [], entities: [], relations: [], domains: [], shapes: [], lines: [], comments: [], warnings: [], px: 1, viewFormat: '0',
stats: { tables: 0, columns: 0, fks: 0, pages: 0, external: 0, lines: 0, stdEntities: 0 } };
var byName = {}, pi, ti, ei, ci;
var lines = [], symbolLines = 0, dupNames = {};
var masters = {}, mk; // ★No.209: マスター ID → 先頭図形 (木)
if (bundle.masters) for (mk in bundle.masters) if (bundle.masters.hasOwnProperty(mk)) { var mtops = _vsdxShapes(bundle.masters[mk]); if (mtops.length) masters[mk] = mtops[0]; }
// ★No.212 / 222: 標準ステンシル (クロウフット / IDEF1X)。 stdLines = 関係図形 (端記号つき)、 owners = ページ ID → 図形 ID → 持ち主 (校閲のコメントの宛先)
var std = _vsdxStdMasters(masters), stdLines = [], owners = {}, strayAttrs = 0;
if (std.idef) res.viewFormat = '1';
if (std.any) res.nonDepDash = true; // ★No.255: Visio のカラスの足は「識別の設定」オフを破線で描く → A5M2 の UseNondependenceDashLine=1
var STD_CARD = { '29': '3', '28': '4', '25': '2', '30': '1', '42': '3', '22': '1' }; // Visio の端記号 → A5M2 RelationType (3 = 0以上 / 4 = 1以上 / 2 = 1 / 1 = 0または1)
function stdCard(v, dflt) { v = String(v == null ? '' : v).replace(/\s/g, ''); if (v === '0') return '2'; return STD_CARD[v] || dflt; } // 0 = 「既定値」(記号なし) = 1 つのみ
function stdOf(sh) { return !!(std.any && sh.master && std.role[sh.master]); }
function num0(v) { var n = parseFloat(v); return isNaN(n) ? 0 : n; }
function slotChild(sh, slot) { var i, r; for (i = 0; i < sh.children.length; i++) { if (sh.children[i].masterShape === slot) return sh.children[i]; r = slotChild(sh.children[i], slot); if (r) return r; } return null; }
function entity(name) {
var e = byName[name];
if (!e) { e = { pname: name, lname: name, comment: '', attrs: [], pos: {}, bkColor: '$FFFFFF', _keys: {}, _ext: false }; byName[name] = e; res.entities.push(e); }
return e;
}
for (pi = 0; pi < (bundle.pages || []).length; pi++) {
var pg = bundle.pages[pi], pageName = pg.name || ('Page-' + (pi + 1)), pageH = parseFloat(pg.h) || 0;
res.pages.push({ name: pageName });
var tops = _vsdxFlatten(_vsdxShapes(pg.xml || ''), masters, stdOf), conns = _vsdxConnects(pg.xml || ''), entOf = {}, connectorIds = [], plain = {}; // No.209 / No.210
var pageId = pg.id != null ? String(pg.id) : String(pi), stdEnts = [], stdAttrs = [], stdRelShapes = [];
if (!owners[pageId]) owners[pageId] = {};
var connectedIds = {}, ck0; // ★No.253: 線でつながれた図形 (名前だけの参照エンティティ) は図形扱いにしない
// ★No.260: 入れ子の図形 (エンティティのグループの中の枠や区切り線) → 最上位の図形。 関係図形の端がそこに接着されていてもエンティティに解決する
var topOf = {}, walkTop = function (n, top) { var wi; for (wi = 0; wi < (n.children || []).length; wi++) { topOf[n.children[wi].id] = top; walkTop(n.children[wi], top); } };
for (ti = 0; ti < tops.length; ti++) walkTop(tops[ti], tops[ti].id);
var entAt = function (sid) { return entOf[sid] || (topOf[sid] != null ? entOf[topOf[sid]] : null) || null; };
// ★No.260: 接着されていない端 (Connect が無い = エンティティに重ねただけ) は、 端の座標 (inch、 y は下が原点) が載っているエンティティの最上位図形
// (無ければ 0.3 in 以内で一番近い箱) に解決する (テスターの再現: 従業員 → トレーニング履歴 の終点が接着されておらず線が落ちた)
var entNear = function (xs, ys) {
var x = parseFloat(xs), y = parseFloat(ys), best = null, bestD = 0.3, ni;
if (isNaN(x) || isNaN(y)) return null;
for (ni = 0; ni < tops.length; ni++) {
var tg = tops[ni], tc = tg.cells || {};
if (!entOf[tg.id] || tc.PinX == null || tc.PinY == null || tc.Width == null || tc.Height == null) continue;
var px = parseFloat(tc.PinX) || 0, py = parseFloat(tc.PinY) || 0, tw = parseFloat(tc.Width) || 0, th = parseFloat(tc.Height) || 0;
var lx = px - (tc.LocPinX != null ? parseFloat(tc.LocPinX) : tw / 2), by = py - (tc.LocPinY != null ? parseFloat(tc.LocPinY) : th / 2);
var dx = x < lx ? lx - x : (x > lx + tw ? x - lx - tw : 0), dy = y < by ? by - y : (y > by + th ? y - by - th : 0), d = Math.sqrt(dx * dx + dy * dy);
if (d < bestD) { bestD = d; best = entOf[tg.id]; }
}
return best;
};
for (ck0 in conns) if (conns.hasOwnProperty(ck0)) { if (conns[ck0].begin) connectedIds[conns[ck0].begin] = 1; if (conns[ck0].end) connectedIds[conns[ck0].end] = 1; }
for (ti = 0; ti < tops.length; ti++) {
var g = tops[ti];
// ★No.253: 標準ステンシルの図の、 マスターを持たない図形 (四角形 / 楕円 / 直線 / 文字だけ) → [Shape] / [Line]。 重なり順 = ページ内の出現順 (後が手前)。
// T字形 / PRIDE の図 (std.any = false) は従来どおり触らない
if (std.any && !g.master && !(g.children && g.children.length) && (g.geo || []).length && !connectedIds[g.id]) {
var zA = (pg._z = (pg._z || 0) + 1), cA = g.cells || {}, IN2 = 254;
var lpat = String(cA.LinePattern == null ? '1' : cA.LinePattern), fpat = String(cA.FillPattern == null ? '1' : cA.FillPattern);
var ltA = lpat === '0' ? 1 : (parseInt(lpat, 10) > 1 ? 2 : 0);
if (cA.BeginX != null && cA.EndX != null && g.geo.length <= 2) { // 1-D 図形 = 直線 (Begin → End。 inch、 y は下が原点)
var bxL = parseFloat(cA.BeginX) || 0, byL = parseFloat(cA.BeginY) || 0, exL = parseFloat(cA.EndX) || 0, eyL = parseFloat(cA.EndY) || 0;
res.lines.push({ page: pageName, x: Math.round(bxL * IN2), y: Math.round((pageH - byL) * IN2), w: Math.round((exL - bxL) * IN2), h: Math.round((byL - eyL) * IN2),
lineColor: cA.LineColor ? _vsdxColor(cA.LineColor) : '', lineWidth: '', lineType: ltA,
startTerm: (cA.BeginArrow != null && String(cA.BeginArrow) !== '0') ? 4 : 0,
endTerm: (cA.EndArrow != null && String(cA.EndArrow) !== '0') ? 4 : 0, z: zA });
continue;
}
var bxA = _vsdxBox(cA, pageH), txA = String(g.text || '').replace(/\r\n?/g, '\n').replace(/\s+$/, ''), isText = (fpat === '0' && lpat === '0');
res.shapes.push({ page: pageName, x: bxA.x, y: bxA.y, w: bxA.w, h: bxA.h,
shapeType: (g.geo.indexOf('Ellipse') >= 0) ? 'Ellipse' : 'Rectangle', text: txA,
lineType: ltA, brushAlpha: isText ? 0 : null,
lineColor: (!isText && cA.LineColor) ? _vsdxColor(cA.LineColor) : '',
brushColor: (!isText && fpat !== '0' && cA.FillForegnd) ? _vsdxColor(cA.FillForegnd) : '',
lineWidth: '', fontColor: cA.Color ? _vsdxColor(cA.Color) : '', fontSize: 0, fontBold: false, z: zA });
continue;
}
var role = stdOf(g) ? std.role[g.master] : '';
if (role === 'sep') continue;
if (role === 'rel') { stdRelShapes.push(g); continue; }
if (role === 'attr') { stdAttrs.push(g); continue; }
if (role === 'ent') {
// 標準ステンシルのエンティティ: 名前 = User.EntityName (無ければ名前の子図形の文字)。 既定の「エンティティ名」のままは置かない
var en = String((g.user && g.user.EntityName) || '').replace(/[\s\u3000]+/g, ''), ci5;
for (ci5 = 0; ci5 < g.children.length && !en; ci5++) en = String(g.children[ci5].text || '').replace(/[\s\u3000]+/g, '');
if (!en || /^(エンティティ名|EntityName)$/i.test(en)) continue;
if (byName[en] && byName[en].pos[pageName] && !byName[en]._ext) { dupNames[en] = (dupNames[en] || 1) + 1; en = en + '_' + dupNames[en]; }
var se = entity(en);
if (se._ext) { se._ext = false; se.comment = ''; }
if (g.cells.FillForegnd) se.bkColor = _vsdxColor(g.cells.FillForegnd);
se.pos[pageName] = _vsdxBox(g.cells, pageH);
entOf[g.id] = se; owners[pageId][g.id] = { e: se };
for (ci5 = 0; ci5 < g.children.length; ci5++) { entOf[g.children[ci5].id] = se; owners[pageId][g.children[ci5].id] = { e: se }; }
var ew = num0(g.cells.Width), eh = num0(g.cells.Height);
var elx = g.cells.LocPinX != null ? num0(g.cells.LocPinX) : ew / 2, ely = g.cells.LocPinY != null ? num0(g.cells.LocPinY) : eh / 2;
stdEnts.push({ g: g, e: se, left: num0(g.cells.PinX) - elx, bottom: num0(g.cells.PinY) - ely, w: ew, h: eh, cols: [] });
continue;
}
if (g.cells.BeginX != null && g.cells.EndX != null) { connectorIds.push(g.id); continue; }
var te = _vsdxEntity(g);
if (te) {
if (byName[te.name] && byName[te.name].pos[pageName] && !byName[te.name]._ext) {
dupNames[te.name] = (dupNames[te.name] || 1) + 1;
te.name = te.name + '_' + dupNames[te.name];
}
var e = entity(te.name);
if (e._ext || !e.attrs.length) { e._ext = false; _vsdxAddCols(e, te.pkLines, true); _vsdxAddCols(e, te.attrLines, false); e.comment = ''; }
e.bkColor = _vsdxColor(te.color);
e.pos[pageName] = _vsdxBox(g.cells, pageH);
entOf[g.id] = e; owners[pageId][g.id] = { e: e };
for (ci = 0; ci < g.children.length; ci++) { entOf[g.children[ci].id] = e; owners[pageId][g.children[ci].id] = { e: e }; }
} else if (!g.children.length) {
var t1 = _vsdxLines(g.text);
if (t1.length === 1 && !/^【/.test(t1[0]) && !/^(A|B|汎化)$/.test(t1[0])) plain[g.id] = { name: t1[0].replace(/[\s\u3000]+/g, ''), cells: g.cells };
}
}
// ★No.212 / 222: 標準ステンシルの属性 → 入っているエンティティ (座標)。 並びは User.ItemIndex (無ければ上から)。 属性はそのエンティティを最初に
// 読んだページでだけ入れる (T字形と同じ)。 主キー = Primary Key Attribute のマスター (User.PrimaryKey=1)、 外部キー = User.ForeignKey か名前の (FK)。
// 型 = インスタンスが上書きした User.AttributeType (IDEF1X) / 型欄の子図形の文字 (クロウフット)。 上書きが無くエンティティが型を表示しているなら既定の int。
// 図形データ (Prop) の「コメント」「型」行も見る。 NOT NULL = IDEF1X は (O) でない属性、 クロウフットは主キーか必須 (User.Required)
stdAttrs.sort(function (a, b) {
var ia = num0(a.user && a.user.ItemIndex), ib = num0(b.user && b.user.ItemIndex);
if (ia > 0 && ib > 0 && ia !== ib) return ia - ib;
return num0(b.cells.PinY) - num0(a.cells.PinY);
});
for (ti = 0; ti < stdAttrs.length; ti++) {
var ag = stdAttrs[ti], ax = num0(ag.cells.PinX), ay = num0(ag.cells.PinY), best = null, bi;
for (bi = 0; bi < stdEnts.length; bi++) {
var sb = stdEnts[bi];
if (ax < sb.left - 0.05 || ax > sb.left + sb.w + 0.05 || ay < sb.bottom - 0.05 || ay > sb.bottom + sb.h + 0.05) continue;
if (!best || sb.w * sb.h < best.w * best.h) best = sb;
}
if (!best) { strayAttrs++; continue; }
best.cols.push(ag);
entOf[ag.id] = best.e;
}
for (ti = 0; ti < stdEnts.length; ti++) {
var sent = stdEnts[ti], fillCols = !sent.e.attrs.length, ai;
for (ai = 0; ai < sent.cols.length; ai++) {
var ag2 = sent.cols[ai], au = ag2.user || {}, ao = ag2.userOwn || {}, ci6;
var anm = String(au.AttributeName || '').replace(/[\s\u3000]+$/, '').replace(/^[\s\u3000]+/, '');
for (ci6 = 0; ci6 < ag2.children.length && !anm; ci6++) if (ag2.children[ci6].hasText) anm = _vsdxLines(ag2.children[ci6].text).join('');
if (!anm) anm = _vsdxLines(ag2.text).join('');
if (!anm) continue;
var apk = !!std.pk[ag2.master] || String(au.PrimaryKey) === '1', col = _vsdxCol(anm, apk);
if (!col.lname) continue;
if (String(au.ForeignKey) === '1') col.fk = true;
col.comment = '';
col.notNull = std.idef ? String(au.OptionalAttr) !== '1' : (apk || String(au.Required) === '1');
// 型: 上書き (インスタンス自身の AttributeType / 型欄の子図形の Text) → 型を表示しているなら継承した既定値
var slot = std.typeSlot[ag2.master], own = ao.AttributeType ? String(au.AttributeType) : null, inh = au.AttributeType != null ? String(au.AttributeType) : null;
var tsl = slot != null ? slotChild(ag2, slot) : null; // 型欄の子図形 (インスタンス自身の子 = 直下 / マスターから複製 = 入れ子の中)
if (tsl) {
if (tsl.hasText && String(tsl.text).replace(/[\s\u3000]/g, '')) own = own != null ? own : _vsdxLines(tsl.text).join(' ');
else if (inh == null) inh = _vsdxLines(tsl.text).join(' ');
}
var showType = String(ao.ShowType ? au.ShowType : ((sent.g.user && sent.g.user.ShowType) || '0')) === '1';
col.type = String(own != null ? own : (showType && inh != null ? inh : '')).replace(/[\s\u3000]+$/, '').replace(/^[\s\u3000]+/, '');
var cmts = [], pi3, pr;
for (pi3 = 0; pi3 < (ag2.prop || []).length; pi3++) {
pr = ag2.prop[pi3];
if (!pr.value) continue;
if (/^(コメント|備考|説明|定義|comment|note|description|definition|remarks?)$/i.test(pr.label)) cmts.push(pr.value);
else if (!col.type && /^(型|データ型|type|data ?type)$/i.test(pr.label)) col.type = pr.value;
}
col.comment = cmts.join('\n');
owners[pageId][ag2.id] = { e: sent.e, col: col };
if (!fillCols || sent.e._keys[col.lname]) { if (!fillCols) { var fc = null, fi; for (fi = 0; fi < sent.e.attrs.length; fi++) if (sent.e.attrs[fi].lname === col.lname) fc = sent.e.attrs[fi]; if (fc) owners[pageId][ag2.id] = { e: sent.e, col: fc }; } continue; }
sent.e._keys[col.lname] = 1;
sent.e.attrs.push(col);
}
var pj; // エンティティの図形データ「コメント」行
for (pj = 0; pj < (sent.g.prop || []).length; pj++) if (sent.g.prop[pj].value && /^(コメント|備考|説明|定義|comment|note|description|definition|remarks?)$/i.test(sent.g.prop[pj].label) && sent.e.comment.indexOf(sent.g.prop[pj].value) < 0) sent.e.comment = sent.e.comment ? sent.e.comment + '\n' + sent.g.prop[pj].value : sent.g.prop[pj].value;
}
res.stats.stdEntities += stdEnts.length;
// 標準ステンシルの関係図形: 両端 (Connects の ToSheet = エンティティか属性の図形) と端記号を控える (向きと列は全ページを読んでから)
for (ti = 0; ti < stdRelShapes.length; ti++) {
var rg = stdRelShapes[ti], rc = conns[rg.id];
var eA = rc && rc.begin ? entAt(rc.begin) : null, eB = rc && rc.end ? entAt(rc.end) : null; // ★No.260: 入れ子の図形への接着も
if (!eA && !(rc && rc.begin)) eA = entNear(rg.cells.BeginX, rg.cells.BeginY); // ★No.260: 接着されていない端は座標で
if (!eB && !(rc && rc.end)) eB = entNear(rg.cells.EndX, rg.cells.EndY);
if (!eA || !eB) { symbolLines++; continue; }
stdLines.push({ a: eA, b: eB, page: pageName, rtA: stdCard(rg.cells.BeginArrow, '3'), rtB: stdCard(rg.cells.EndArrow, '2'),
caption: String((rg.user && rg.user.RelationshipName) || '').replace(/[\s\u3000]+$/, '').replace(/^[\s\u3000]+/, ''),
ident: (rg.userOwn && rg.userOwn.Identifying && rg.user && rg.user.Identifying != null) ? String(rg.user.Identifying) : null, // ★No.255: 識別の設定 (図形自身が持つ行だけ。 マスターの既定は見ない = 無ければ FK が主キーかで決める)
route: _vsdxConnRoute(rg, pageH) }); // ★No.256: 線の経路
}
// 線: 両端の図形 → エンティティ (グループ / 子 / 名前だけの図形 = 参照エンティティ)
for (ti = 0; ti < connectorIds.length; ti++) {
var cn = conns[connectorIds[ti]];
if (!cn || !cn.begin || !cn.end) continue;
var ends = [], k, hit = 0;
for (k = 0; k < 2; k++) {
var sid = k ? cn.end : cn.begin, e2 = entAt(sid); // ★No.260
if (!e2 && plain[sid]) {
e2 = entity(plain[sid].name);
if (!e2.pos[pageName]) { e2.pos[pageName] = _vsdxBox(plain[sid].cells, pageH); }
if (!e2.attrs.length) { e2._ext = true; e2.comment = 'Visio では名前だけの参照 (属性は他の図で定義)'; }
entOf[sid] = e2;
}
if (e2) hit++;
ends.push(e2 || null);
}
if (hit === 2) lines.push({ a: ends[0], b: ends[1], page: pageName });
else symbolLines++;
}
}
// ★No.212 / 222: 校閲のコメント (visio/comments.xml) → 付けた図形の持ち主 (エンティティ / 標準ステンシルの属性) のコメント
var cmtList = bundle.comments || [], oc;
for (ti = 0; ti < cmtList.length; ti++) {
oc = owners[String(cmtList[ti].page)] && owners[String(cmtList[ti].page)][String(cmtList[ti].shape)];
if (!oc) continue;
var ctgt = oc.col || oc.e;
ctgt.comment = ctgt.comment ? ctgt.comment + '\n' + cmtList[ti].text : cmtList[ti].text;
}
// ---- リレーション ----
// 1) 線: 両端 A / B のうち、 相手の名前か相手の PK の core と一致する FK (または依存キー) を持つ側を子にする。 複合キーはまとめて 1 本
// 2) 線に使われなかった FK: 名前の規約 (完全一致 → 接尾 → 接頭)。 PK 名だけの照合はその core を PK に持つエンティティが 1 つのときだけ
var names = [], byPkCore = {}, pkCoreCount = {}, n2;
for (ei = 0; ei < res.entities.length; ei++) {
names.push(res.entities[ei].pname);
// 識別子の持ち主 = FK でない PK 列を持つエンティティ (サブタイプや子は同じ識別子を (FK) で持つので除く)
for (ci = 0; ci < res.entities[ei].attrs.length; ci++) if (res.entities[ei].attrs[ci].pk && !res.entities[ei].attrs[ci].fk) {
var pc = _vsdxCore(res.entities[ei].attrs[ci].lname), ownPk = true;
if (!pc || !ownPk) continue;
if (!byPkCore[pc]) byPkCore[pc] = res.entities[ei];
pkCoreCount[pc] = (pkCoreCount[pc] || 0) + 1;
}
}
names.sort(function (a, b) { return b.length - a.length; });
var relKey = {}, unresolved = [], polymorphic = [], used = {}, sameName = [], relByPair = {}; // sameName: 線も (FK) も無い同名の識別子 (No.211、 警告だけ) / relByPair: 親\t子 → 関係 (No.213)
// core が何かのエンティティ名 (完全一致 / 接尾 / 接頭) に当たるか (No.215: 当たらない (FK) 列は線の相手を親にする)
// ★No.259: 自分のエンティティ名 (商品 の 商品主幹者コード の接頭 商品 等) は当たりにしない (当てると線の fallback から外れて 2 本目の線が捨てられた)
function nameLike(core, selfEnt) {
var i6, n6, selfNm = selfEnt ? selfEnt.pname.replace(/_\d+$/, '') : null;
if (!core) return false;
if (byName[core] && byName[core] !== selfEnt) return true;
for (i6 = 0; i6 < names.length; i6++) {
n6 = names[i6];
if (selfNm != null && (n6 === selfNm || n6 === selfEnt.pname || _vsdxCore(n6) === _vsdxCore(selfNm))) continue;
if (n6.length >= 2 && core.length > n6.length && (core.substring(core.length - n6.length) === n6 || core.substring(0, n6.length) === n6)) return true;
}
return false;
}
// FK らしい列 = (FK) 付き、 または依存キー (PK の core が他のエンティティ名)。 自分の名前 (同名の _2 も含む) と同じ core の PK は自分の識別子
function isFkLike(t, c) {
var core = _vsdxCore(c.lname);
if (core === _vsdxCore(t.pname.replace(/_\d+$/, ''))) return !!c.fk;
return c.fk || (c.pk && byName[core] && byName[core] !== t);
}
function markerOf(nm) { return /[#C]$/.test(nm) ? nm.charAt(nm.length - 1) : ''; }
function parentPkFor(parent, core, marker) {
var i3;
for (i3 = 0; i3 < parent.attrs.length; i3++) if (parent.attrs[i3].pk && _vsdxCore(parent.attrs[i3].lname) === core) return parent.attrs[i3].lname;
for (i3 = 0; i3 < parent.attrs.length; i3++) if (parent.attrs[i3].pk) return parent.attrs[i3].lname;
var nm = core + marker, c0 = _vsdxCol(nm, true); // 参照エンティティ (属性なし): 子の FK 名を主キーとして補う
if (!parent._keys[nm]) { parent._keys[nm] = 1; parent.attrs.push(c0); }
return nm;
}
function addRel(parent, child, pcols, ccols, dep, page, opts) { // opts (No.212 / 222): 標準ステンシルの多重度 rt1 / rt2 と名前 caption
var key = parent.pname + '\t' + child.pname + '\t' + ccols.join(','), i4;
if (relKey[key]) {
if (page && relKey[key].pages.indexOf(page) < 0) relKey[key].pages.push(page);
if (opts && opts.route && page && !(relKey[key].routes && relKey[key].routes[page])) { if (!relKey[key].routes) relKey[key].routes = {}; relKey[key].routes[page] = { pts: opts.route }; }
return relKey[key];
}
var r = { parent: parent.pname, child: child.pname, parentCols: pcols, childCols: ccols, dep: !!dep, rt1: (opts && opts.rt1) || '2', rt2: (opts && opts.rt2) || '3',
caption: (opts && opts.caption) || '', pname: '', pages: page ? [page] : [] };
if (opts && opts.route && page) r.routes = {}, r.routes[page] = { pts: opts.route }; // ★No.256: 線の経路 (書き出しが端子の位置 + 自由結線にする)
relKey[key] = r; res.relations.push(r);
if (!relByPair[parent.pname + '\t' + child.pname]) relByPair[parent.pname + '\t' + child.pname] = r;
for (i4 = 0; i4 < ccols.length; i4++) used[child.pname + '\t' + ccols[i4]] = 1;
return r;
}
// 子の core が親の core と一致 (または役割接頭辞つき: 供給受付申込 → 申込、 親申込 → 申込) なら親の core を返す
function _vsdxCoreMatch(cores, core) {
var k, best = null;
if (cores[core]) return core;
for (k in cores) if (cores.hasOwnProperty(k) && k.length >= 2 && core.length > k.length && core.substring(core.length - k.length) === k && (!best || k.length > best.length)) best = k;
return best;
}
// 親 a の識別 (名前 + PK の core) に当たる子 b の FK 列
// ★No.259: fb = 名前が親に当たらない未使用の (FK) 列を使う fallback を許すか (両方向の名前照合で決まらなかったときだけ true で呼ぶ)
function _vsdxRelFromLine(a, b, fb) {
var cores = {}, i5, cols = [], pcore = [], dep = false;
cores[_vsdxCore(a.pname)] = 1;
for (i5 = 0; i5 < a.attrs.length; i5++) if (a.attrs[i5].pk) cores[_vsdxCore(a.attrs[i5].lname)] = 1;
for (i5 = 0; i5 < b.attrs.length; i5++) {
var c = b.attrs[i5];
if ((!isFkLike(b, c) && !c.pk) || (a === b && c.pk && !c.fk)) continue; // 自己参照: 自分の主キーそのものは除く
var core = _vsdxCore(c.lname), hit = _vsdxCoreMatch(cores, core);
if (hit && !used[b.pname + '\t' + c.lname]) { cols.push(c); pcore.push(hit); if (c.pk) dep = true; }
}
if (!cols.length && a !== b && fb) {
// ★No.215: 線はあるが名前が親に当たらない (FK) 列 (担当者ID(FK) → 従業員) = 線が関係を宣言しているので、 他のエンティティ名にも当たらない
// 未使用の (FK) 列を 1 つ使い、 親側は親の主キー
for (i5 = 0; i5 < b.attrs.length; i5++) {
var cf = b.attrs[i5];
if (!cf.fk || used[b.pname + '\t' + cf.lname] || nameLike(_vsdxCore(cf.lname), b)) continue;
cols.push(cf); pcore.push(_vsdxCore(cf.lname)); if (cf.pk) dep = true;
break;
}
}
if (!cols.length) return false;
var pcols = [], ccols = [];
for (i5 = 0; i5 < cols.length; i5++) { pcols.push(parentPkFor(a, pcore[i5], markerOf(cols[i5].lname))); ccols.push(cols[i5].lname); }
addRel(a, b, pcols, ccols, dep, null);
return true;
}
// ★No.212 / 222: 標準ステンシルの関係図形。 端記号から多重度と向き (「多」の側が子。 1 対 1 は FK を持つ側が子、 無ければ始点が子 = ステンシルの既定の向き。
// どちらも多 = 多対多で列なし)。 列 = 子の (FK) 属性 (または主キー) と親の主キーの同名 → 無ければ未使用の (FK) 列を順に親の主キーと組にする。
// 依存 = FK 列が子の主キー (Visio の「識別の設定」は既定が識別のまま残ることが多いので見ない)。 同じ組の 2 本目 (別ページの同じ線) はページを足すだけ
function stdFkCols(child, parent) {
var pks = [], i, j, out = [], taken = {};
for (i = 0; i < parent.attrs.length; i++) if (parent.attrs[i].pk) pks.push(parent.attrs[i].lname);
for (i = 0; i < pks.length; i++) for (j = 0; j < child.attrs.length; j++) {
var c = child.attrs[j];
if (taken[j] || used[child.pname + '\t' + c.lname] || !(c.fk || c.pk) || c.lname !== pks[i] || (child === parent && !c.fk)) continue;
out.push({ p: pks[i], c: c }); taken[j] = 1; break;
}
if (!out.length) {
var k = 0;
for (j = 0; j < child.attrs.length && k < pks.length; j++) { var cf = child.attrs[j]; if (!cf.fk || used[child.pname + '\t' + cf.lname]) continue; out.push({ p: pks[k++], c: cf }); }
}
return out;
}
for (ti = 0; ti < stdLines.length; ti++) {
var sl = stdLines[ti], manyA = sl.rtA === '3' || sl.rtA === '4', manyB = sl.rtB === '3' || sl.rtB === '4', par, chi, rtP, rtC, mm = false;
if (manyA && !manyB) { par = sl.b; chi = sl.a; rtP = sl.rtB; rtC = sl.rtA; }
else if (!manyA && manyB) { par = sl.a; chi = sl.b; rtP = sl.rtA; rtC = sl.rtB; }
else if (manyA && manyB) { par = sl.b; chi = sl.a; rtP = sl.rtB; rtC = sl.rtA; mm = true; }
else {
var fkB = stdFkCols(sl.b, sl.a), fkA = stdFkCols(sl.a, sl.b);
if (fkB.length && !fkA.length) { par = sl.a; chi = sl.b; rtP = sl.rtA; rtC = sl.rtB; } else { par = sl.b; chi = sl.a; rtP = sl.rtB; rtC = sl.rtA; }
}
var pairs = mm ? [] : stdFkCols(chi, par), pc = [], cc = [], sdep = false, pi2;
var exR = relByPair[par.pname + '\t' + chi.pname];
if (!pairs.length && exR) {
if (exR.pages.indexOf(sl.page) < 0) exR.pages.push(sl.page);
if (sl.route && !(exR.routes && exR.routes[sl.page])) { if (!exR.routes) exR.routes = {}; exR.routes[sl.page] = { pts: sl.route }; } // ★No.256
continue;
}
for (pi2 = 0; pi2 < pairs.length; pi2++) { pc.push(pairs[pi2].p); cc.push(pairs[pi2].c.lname); if (pairs[pi2].c.pk) sdep = true; }
if (sl.ident === '1') sdep = true; else if (sl.ident === '0') sdep = false; // ★No.255: Visio の「識別の設定」が優先
addRel(par, chi, pc, cc, sdep, sl.page, { rt1: rtP, rt2: rtC, caption: sl.caption, route: sl.route });
}
var noFk = {};
for (ti = 0; ti < lines.length; ti++) {
var ln2 = lines[ti], okLine = false, sameR = null;
if (ln2.a !== ln2.b) {
// ★No.213: 同じ向きの関係が既にある組 (別ページの同じ線) は、 その関係にページを足すだけ。 逆向きに作り直さない
// (2 ページ目で 受注明細 → 受注 が出来て 受注 の主キーに (FK) が付いた)
// ★No.259: 順序 = 名前照合 a→b → 別ページの同じ線 a→b (No.213) → 名前照合 b→a → 別ページの同じ線 b→a → fallback (名前が親に当たらない未使用の (FK) 列) a→b / b→a。
// 「同じ線」は別ページのときだけ (同じページの 2 本目 = FK を 2 つ持つ = 別の関係で、 fallback が次の未使用の (FK) 列で作る)。 作れなければ警告へ
var sameOn = function (k) { var r0 = relByPair[k]; return (r0 && r0.pages.indexOf(ln2.page) < 0) ? r0 : null; };
okLine = _vsdxRelFromLine(ln2.a, ln2.b, false);
if (!okLine) sameR = sameOn(ln2.a.pname + '\t' + ln2.b.pname);
if (!okLine && !sameR) { okLine = _vsdxRelFromLine(ln2.b, ln2.a, false); if (!okLine) sameR = sameOn(ln2.b.pname + '\t' + ln2.a.pname); }
if (!okLine && !sameR) okLine = _vsdxRelFromLine(ln2.a, ln2.b, true) || _vsdxRelFromLine(ln2.b, ln2.a, true);
} else okLine = _vsdxRelFromLine(ln2.a, ln2.a, false); // 自己参照 (階層)
if (sameR) { if (sameR.pages.indexOf(ln2.page) < 0) sameR.pages.push(ln2.page); continue; }
if (!okLine) noFk[ln2.a.pname + ' ⇔ ' + ln2.b.pname] = 1;
else { var lastR = res.relations[res.relations.length - 1]; if (lastR.pages.indexOf(ln2.page) < 0) lastR.pages.push(ln2.page); }
}
// 線で結ばれなかった FK を名前の規約で
function findParent(core) {
var i2;
if (!core) return null;
if (byName[core]) return byName[core];
for (i2 = 0; i2 < names.length; i2++) { n2 = names[i2]; if (n2.length >= 2 && core.length > n2.length && core.substring(core.length - n2.length) === n2) return byName[n2]; }
for (i2 = 0; i2 < names.length; i2++) { n2 = names[i2]; if (n2.length >= 2 && core.length > n2.length && core.substring(0, n2.length) === n2) return byName[n2]; }
return (byPkCore[core] && pkCoreCount[core] === 1) ? byPkCore[core] : null;
}
for (ei = 0; ei < res.entities.length; ei++) {
var t = res.entities[ei];
for (ci = 0; ci < t.attrs.length; ci++) {
var c2 = t.attrs[ci];
// ★Ver1.0.22 (No.211): 線で結ばれていない列を名前で結ぶのは (FK) と書いた列だけ。 他のエンティティ名と同じ識別子 (依存キー) は線がある
// ときだけ (_vsdxRelFromLine)。 線も (FK) も無い同名の識別子は別物として扱う (テスター意図)
if (used[t.pname + '\t' + c2.lname]) continue;
if (!c2.fk) { if (isFkLike(t, c2)) sameName.push(t.pname + '.' + c2.lname); continue; } // 自分の名前と同じ識別子 (顧客_2.顧客#) は除く
var core2 = _vsdxCore(c2.lname), parent = findParent(core2);
if (!parent || parent === t) { (/設備/.test(core2) ? polymorphic : unresolved).push(t.pname + '.' + c2.lname); continue; }
addRel(parent, t, [parentPkFor(parent, core2, markerOf(c2.lname))], [c2.lname], c2.pk, null);
}
}
res.stats.lines = lines.length + stdLines.length;
var noFkList = [], nk;
for (nk in noFk) if (noFk.hasOwnProperty(nk)) noFkList.push(nk);
// 集計と警告
for (ei = 0; ei < res.entities.length; ei++) {
var e3 = res.entities[ei];
if (e3._ext) res.stats.external++;
res.stats.columns += e3.attrs.length;
delete e3._keys; delete e3._ext;
}
res.stats.tables = res.entities.length; res.stats.fks = res.relations.length; res.stats.pages = res.pages.length;
if (res.stats.external) res.warnings.push(res.stats.external + ' 件は名前だけの参照エンティティ (Visio に属性が無い。 FK 名から主キーだけ補った)');
if (unresolved.length) res.warnings.push('親エンティティが見つからない FK ' + unresolved.length + ' 件 (他の図で定義されたエンティティへの参照など): ' + unresolved.slice(0, 20).join(', ') + (unresolved.length > 20 ? ' …' : ''));
if (polymorphic.length) res.warnings.push('設備への多態参照 (点設備・線設備のいずれかを指し 1 つに決められない) ' + polymorphic.length + ' 件はリレーションにしていません: ' + polymorphic.slice(0, 8).join(', ') + (polymorphic.length > 8 ? ' …' : ''));
if (noFkList.length) res.warnings.push('線はあるが FK 名で結べない組 ' + noFkList.length + ' 件 (サブタイプ等。 リレーションにしていない): ' + noFkList.slice(0, 15).join(', ') + (noFkList.length > 15 ? ' …' : ''));
if (symbolLines) res.warnings.push('記号や凡例につながる線 ' + symbolLines + ' 本は変換していません');
if (strayAttrs) res.warnings.push('どのエンティティにも入っていない属性の図形 ' + strayAttrs + ' 件は変換していません (標準ステンシル)');
if (sameName.length) res.warnings.push('他のエンティティと同名の識別子 ' + sameName.length + ' 件は線も (FK) も無いためリレーションにしていません: ' + sameName.slice(0, 15).join(', ') + (sameName.length > 15 ? ' …' : ''));
var dupList = [];
for (nk in dupNames) if (dupNames.hasOwnProperty(nk)) dupList.push(nk);
if (dupList.length) res.warnings.push('同じ名前のエンティティが複数あるため _2 … を付けた: ' + dupList.join(', '));
return res;
}
function _vsdxUnzip(buf, wantRe, raw) { // wantRe = 取り出す項目 (既定 = Visio のページ XML)、 raw = 文字列にせずバイトのまま返す (astah の EntityStore)
var u8 = new Uint8Array(buf), n = u8.length, dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength), i, k;
function u16(p) { return dv.getUint16(p, true); }
function u32(p) { return dv.getUint32(p, true); }
var eocd = -1;
for (i = n - 22; i >= 0 && i >= n - 70000; i--) if (u32(i) === 0x06054b50) { eocd = i; break; }
if (eocd < 0) return Promise.reject(new Error('not a zip (vsdx / asta) file'));
var count = u16(eocd + 10), p = u32(eocd + 16), entries = [], dec = new TextDecoder('utf-8');
for (k = 0; k < count; k++) {
if (u32(p) !== 0x02014b50) break;
var nlen = u16(p + 28), elen = u16(p + 30), clen = u16(p + 32);
entries.push({ name: dec.decode(u8.subarray(p + 46, p + 46 + nlen)), method: u16(p + 10), csize: u32(p + 20), loff: u32(p + 42) });
p += 46 + nlen + elen + clen;
}
var want = [], out = {}, re = wantRe || /^visio\/(pages\/(pages\.xml|page\d+\.xml|_rels\/pages\.xml\.rels)|masters\/(masters\.xml|master\d+\.xml|_rels\/masters\.xml\.rels)|comments\.xml)$/; // No.212 / 222: 校閲のコメントも
for (k = 0; k < entries.length; k++) if (re.test(entries[k].name)) want.push(entries[k]);
function inflate(e) {
var lp = e.loff, dstart = lp + 30 + u16(lp + 26) + u16(lp + 28), data = u8.subarray(dstart, dstart + e.csize);
if (e.method === 0) return Promise.resolve(data);
if (e.method !== 8) return Promise.reject(new Error('unsupported zip method ' + e.method));
var ds = new DecompressionStream('deflate-raw');
return new Response(new Blob([data]).stream().pipeThrough(ds)).arrayBuffer().then(function (ab) { return new Uint8Array(ab); });
}
var chain = Promise.resolve();
want.forEach(function (e) { chain = chain.then(function () { return inflate(e).then(function (bytes) { out[e.name] = raw ? bytes : dec.decode(bytes); }); }); });
return chain.then(function () { return out; });
}
function _vsdxBundle(fileName, files) {
var relMap = {}, rels = files['visio/pages/_rels/pages.xml.rels'] || '', m, re = /<Relationship\b([^>]*?)\/?>/g;
while ((m = re.exec(rels))) {
var id = _vsdxAttr(m[1], 'Id'), tg = _vsdxAttr(m[1], 'Target');
if (id && tg) relMap[id] = tg.replace(/^\//, '').replace(/^visio\/pages\//, '');
}
var pages = [], px = files['visio/pages/pages.xml'] || '', pre = /<Page\b([^>]*)>([\s\S]*?)<\/Page>/g, pm, idx = 0;
while ((pm = pre.exec(px))) {
var nm = _vsdxAttr(pm[1], 'Name') || _vsdxAttr(pm[1], 'NameU') || ('Page-' + (idx + 1)), cells = _vsdxCells(pm[2]);
var rm = /<Rel\b[^>]*?r:id\s*=\s*(?:'([^']*)'|"([^"]*)")/.exec(pm[2]), rid = rm ? (rm[1] || rm[2]) : null;
var file = (rid && relMap[rid]) ? ('visio/pages/' + relMap[rid]) : ('visio/pages/page' + (idx + 1) + '.xml');
if (files[file]) pages.push({ name: nm, id: _vsdxAttr(pm[1], 'ID'), w: cells.PageWidth || '', h: cells.PageHeight || '', xml: files[file] }); // id (No.212 / 222): 校閲のコメントの PageID
idx++;
}
// ★No.209: マスター (ステンシル) の図形 XML (ID → XML)。 インスタンスは上書きした値だけを持つので _vsdxParse が継承する
var masters = {}, mrels = {}, mr = files['visio/masters/_rels/masters.xml.rels'] || '', mm;
re.lastIndex = 0;
while ((mm = re.exec(mr))) { var mid = _vsdxAttr(mm[1], 'Id'), mtg = _vsdxAttr(mm[1], 'Target'); if (mid && mtg) mrels[mid] = mtg.replace(/^\//, '').replace(/^visio\/masters\//, ''); }
var mx = files['visio/masters/masters.xml'] || '', mre = /<Master\b([^>]*)>([\s\S]*?)<\/Master>/g, pm2;
while ((pm2 = mre.exec(mx))) {
var mId = _vsdxAttr(pm2[1], 'ID'), rm2 = /<Rel\b[^>]*?r:id\s*=\s*(?:'([^']*)'|"([^"]*)")/.exec(pm2[2]), rid2 = rm2 ? (rm2[1] || rm2[2]) : null;
var mf = (rid2 && mrels[rid2]) ? ('visio/masters/' + mrels[rid2]) : null;
if (mId && mf && files[mf]) masters[mId] = files[mf];
}
return { vsdx: 1, name: String(fileName || '').replace(/\.[^.]*$/, ''), pages: pages, masters: masters, comments: _vsdxComments(files['visio/comments.xml'] || '') };
}
// ============================================================
// astah* professional の ER 図 (.asta) → 変換モデル (Ver1.0.6)
// ・.asta = ZIP。 中の EntityStore が Java 直列化ストリーム (AC ED 00 05 の後に astah 独自の 4 バイト 00 EE 00 01 が入る)。
// ・Java 直列化はクラス記述子 (項目名と型) をストリーム自身が持つので、 クラスを知らなくても構造どおりに読める。
// 独自 writeObject を持つクラス (SC_WRITE_METHOD) の追加データはブロックデータ (読み飛ばし) とオブジェクト (集める) の列で、
// JDK のコレクションはその列が要素 (ArrayList 等) / キーと値の交互 (HashMap 等) なので、 それをほどけばリストと表になる。
// ・ER で使うクラス = EREntityImp (name / taggedValue alias3 = 物理名 / definition / structuralFeature = 属性) /
// ERAttributeImp (constraint = PRIMARY KEY・NOT NULL・FOREIGN KEY・DEFAULT:… / type = UClassifierImp (jude.type = er_datatype か er_Domain) /
// taggedValue jude.modifier = 桁 / referencedPrimaryKey = 親の主キー属性) / ERRelationshipImp (foreignKeys, isIdentifying) /
// ERSubtypeRelationshipImp (supertype / subtype / subTypeForeignKeys / discriminatorAttribute) / UERDiagramImp (name) /
// EREntityPresentation (model / diagram / location Pnt2d / width / height / baseColor) と ER…RelationshipPresentation (diagram)。
// ・座標の単位は astah の 1 px ≒ 1/96 inch = 0.2646 mm → _OBER_PX (2.65) で 0.1 mm に。
// Java の修正 UTF-8 (TC_STRING) → 文字列。 サロゲートは 3 バイトずつ別々に来るので fromCharCode で自然につながる
function _astaUtf(u8, s, n) {
var out = [], cc = [], i = s, e = s + n, c;
while (i < e) {
c = u8[i++];
if (c < 0x80) cc.push(c);
else if ((c & 0xE0) === 0xC0) cc.push(((c & 0x1F) << 6) | (u8[i++] & 0x3F));
else if ((c & 0xF0) === 0xE0) { cc.push(((c & 0x0F) << 12) | ((u8[i] & 0x3F) << 6) | (u8[i + 1] & 0x3F)); i += 2; }
else { // 4 バイト (標準 UTF-8 が混ざったとき)
var cp = ((c & 0x07) << 18) | ((u8[i] & 0x3F) << 12) | ((u8[i + 1] & 0x3F) << 6) | (u8[i + 2] & 0x3F);
i += 3; cp -= 0x10000; cc.push(0xD800 + (cp >> 10), 0xDC00 + (cp & 0x3FF));
}
if (cc.length >= 4096) { out.push(String.fromCharCode.apply(null, cc)); cc = []; }
}
if (cc.length) out.push(String.fromCharCode.apply(null, cc));
return out.join('');
}
// Java 直列化ストリーム → { objs: [{cls, f, ann, list|map}], maxDepth }。 objs = 出現順の全オブジェクト (TC_OBJECT)。
// f = 項目名 → 値 (スーパークラスから順に読み、 同名は下位が勝つ)。 文字列は JS 文字列、 null は null、 配列は {cls, array}。
function _astaDeser(buf) {
var u8 = (buf instanceof Uint8Array) ? buf : new Uint8Array(buf);
var dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength), p = 0, n = u8.length;
if (n < 6 || u8[0] !== 0xAC || u8[1] !== 0xED) throw new Error('EntityStore is not a Java serialization stream');
p = 4;
if (u8[p] === 0x00 && u8[p + 1] === 0xEE) p += 4; // astah の独自ヘッダ 00 EE 00 01
var handles = [], objs = [], depth = 0, maxDepth = 0;
function u8v() { return u8[p++]; }
function i16() { var v = dv.getInt16(p); p += 2; return v; }
function u16() { var v = dv.getUint16(p); p += 2; return v; }
function i32() { var v = dv.getInt32(p); p += 4; return v; }
function i64() { var hi = dv.getInt32(p), lo = dv.getUint32(p + 4); p += 8; return hi * 4294967296 + lo; }
function utf() { var len = u16(), s = _astaUtf(u8, p, len); p += len; return s; }
function prim(tc) {
var v;
if (tc === 'I') return i32();
if (tc === 'Z') return u8[p++] !== 0;
if (tc === 'D') { v = dv.getFloat64(p); p += 8; return v; }
if (tc === 'J') return i64();
if (tc === 'F') { v = dv.getFloat32(p); p += 4; return v; }
if (tc === 'B') return dv.getInt8(p++);
if (tc === 'S') return i16();
if (tc === 'C') return u16();
throw new Error('bad primitive type code ' + tc);
}
function classDesc() {
var tc = u8v(), k;
if (tc === 0x70) return null; // TC_NULL
if (tc === 0x71) return handles[i32() - 0x7E0000]; // TC_REFERENCE
var d = { name: '', flags: 0, fields: [], sup: null };
if (tc === 0x7D) { // TC_PROXYCLASSDESC
handles.push(d);
var ic = i32();
for (k = 0; k < ic; k++) utf();
annotations();
d.sup = classDesc();
return d;
}
if (tc !== 0x72) throw new Error('unexpected tag 0x' + tc.toString(16) + ' (class descriptor) at ' + (p - 1));
d.name = utf(); i64(); // serialVersionUID
handles.push(d);
d.flags = u8v();
var fc = i16();
for (k = 0; k < fc; k++) {
var ft = String.fromCharCode(u8v()), fn = utf(), fcn = '';
if (ft === 'L' || ft === '[') fcn = content(); // クラス名 (TC_STRING / TC_REFERENCE)
d.fields.push({ t: ft, n: fn, c: fcn });
}
annotations(); // クラス注釈 (通常は空)
d.sup = classDesc();
return d;
}
function annotations() { // TC_ENDBLOCKDATA まで: ブロックデータは読み飛ばし、 オブジェクトは集める
var list = [], tc, l, v;
for (;;) {
if (p >= n) throw new Error('unexpected end of stream (block data)');
tc = u8[p];
if (tc === 0x78) { p++; return list; }
if (tc === 0x77) { p++; l = u8v(); p += l; continue; }
if (tc === 0x7A) { p++; l = i32(); p += l; continue; }
v = content();
if (v !== undefined) list.push(v);
}
}
function chain(d) { var c = []; for (var x = d; x; x = x.sup) c.unshift(x); return c; }
function content() {
var tc = u8v(), s, d, o, k;
if (tc === 0x70) return null; // TC_NULL
if (tc === 0x71) return handles[i32() - 0x7E0000]; // TC_REFERENCE
if (tc === 0x74) { s = utf(); handles.push(s); return s; } // TC_STRING
if (tc === 0x7C) { k = i64(); s = _astaUtf(u8, p, k); p += k; handles.push(s); return s; } // TC_LONGSTRING
if (tc === 0x76) { d = classDesc(); handles.push(d); return d; } // TC_CLASS
if (tc === 0x7E) { d = classDesc(); o = { cls: d, enumName: '' }; handles.push(o); o.enumName = content(); return o; } // TC_ENUM
if (tc === 0x75) { // TC_ARRAY
d = classDesc(); o = { cls: d, array: [] }; handles.push(o);
var size = i32(), et = (d && d.name) ? d.name.charAt(1) : 'L';
if (et === 'B') { o.array = u8.subarray(p, p + size); p += size; }
else if (et === 'L' || et === '[') { for (k = 0; k < size; k++) o.array.push(content()); }
else { for (k = 0; k < size; k++) o.array.push(prim(et)); }
return o;
}
if (tc === 0x73) { // TC_OBJECT
d = classDesc(); o = { cls: d, f: {}, ann: null }; handles.push(o); objs.push(o);
if (++depth > maxDepth) maxDepth = depth;
var cs = chain(d);
for (var ci = 0; ci < cs.length; ci++) {
var c = cs[ci];
if (c.flags & 0x04) { // SC_EXTERNALIZABLE
if (!(c.flags & 0x08)) throw new Error('externalizable class ' + c.name + ' without block data');
annotations();
continue;
}
if (!(c.flags & 0x02)) continue; // SC_SERIALIZABLE でない (無いはず)
for (var fi = 0; fi < c.fields.length; fi++) {
var fd = c.fields[fi], fv = (fd.t === 'L' || fd.t === '[') ? content() : prim(fd.t);
// ★No.180: 親クラスと同名のフィールド (UStructuralFeatureImp と UAssociationEndImp の multiplicity / type 等) は
// 親側に値・子側に null が入っている → null で上書きしない (関連の端の多重度と相手のエンティティが消えていた)
if (fv !== null || !(fd.n in o.f)) o.f[fd.n] = fv;
}
if (c.flags & 0x01) { // SC_WRITE_METHOD: 独自 writeObject の分 (コレクションの要素はここに来る)
var an = annotations();
if (an.length) o.ann = o.ann ? o.ann.concat(an) : an;
}
}
depth--;
return o;
}
if (tc === 0x77) { k = u8v(); p += k; return undefined; } // TC_BLOCKDATA (最上位)
if (tc === 0x7A) { k = i32(); p += k; return undefined; } // TC_BLOCKDATALONG
if (tc === 0x79) { handles = []; return undefined; } // TC_RESET
if (tc === 0x78) return undefined; // 迷子の TC_ENDBLOCKDATA
if (tc === 0x7B) throw new Error('TC_EXCEPTION in stream');
throw new Error('unexpected tag 0x' + tc.toString(16) + ' at ' + (p - 1));
}
while (p < n) content();
// JDK のコレクションを JS の配列 / エントリ配列にほどく
for (var oi = 0; oi < objs.length; oi++) {
var ob = objs[oi], nm = ob.cls.name || '', an2 = ob.ann || [];
if (/^java\.util\.(ArrayList|LinkedList|HashSet|LinkedHashSet|TreeSet|ArrayDeque|concurrent\.CopyOnWriteArrayList)$/.test(nm)) ob.list = an2;
else if (/^java\.util\.(Vector|Stack)$/.test(nm)) ob.list = ((ob.f.elementData && ob.f.elementData.array) || []).slice(0, ob.f.elementCount || 0);
else if (/^java\.util\.(HashMap|LinkedHashMap|TreeMap|Hashtable|concurrent\.ConcurrentHashMap)$/.test(nm)) {
ob.map = [];
for (var mi = 0; mi + 1 < an2.length; mi += 2) ob.map.push([an2[mi], an2[mi + 1]]);
}
}
return { objs: objs, maxDepth: maxDepth };
}
// java.awt.Color の value (0xAARRGGBB) → A5M2 の $BBGGRR
function _astaColor(v) {
function h(x) { return (x < 16 ? '0' : '') + x.toString(16).toUpperCase(); }
return '$' + h(v & 255) + h((v >> 8) & 255) + h((v >> 16) & 255);
}
// { asta: 1, name, bytes } (ページ側で ZIP から取り出した EntityStore) → 変換モデル
function _astaParse(input) {
var g = _astaDeser(input.bytes), objs = g.objs, i, k;
var res = { kind: 'asta', name: input.name || '', pages: [], entities: [], relations: [], subtypes: [], domains: [], warnings: [],
comments: [], shapes: [], lines: [], // 図上の注記 (TextPresentation) / 矩形 (RectPresentation) / 直線 (LinePresentation)
viewFormat: '0', // [Manager] ViewFormat: 0=IE / 1=IDEF1X (ER 図の notation)
stats: { tables: 0, columns: 0, fks: 0, pages: 0, domains: 0, subtypes: 0, annotations: 0 } };
var SUB_W = 72 / _OBER_PX, SUB_H = 50 / _OBER_PX; // A5M2 のサブタイプ記号の大きさ (0.1 mm → astah の px)
function cn(o) { return (o && o.cls && o.cls.name) ? o.cls.name.replace(/^.*\./, '') : ''; }
function F(o, key) { return (o && o.f) ? o.f[key] : undefined; }
function body(o) { var b = F(o, 'body'); return typeof b === 'string' ? b : ''; }
function nameOf(o) { return body(F(o, 'name')); }
function listOf(v) { return (v && v.list) ? v.list : []; }
function styleOf(o) { // JomtPresentation.styleMap (HashMap) → {'fill.color': '#RRGGBB', 'line.width': '3', …}
var out = {}, sm = F(o, 'styleMap'), ents = (sm && sm.map) ? sm.map : [];
for (var si = 0; si < ents.length; si++) { var kv = ents[si]; if (kv && kv.length >= 2 && typeof kv[0] === 'string') out[kv[0]] = String(kv[1] == null ? '' : kv[1]); }
return out;
}
function tagsOf(o) {
var t = {}, tv = listOf(F(o, 'taggedValue'));
for (var ti = 0; ti < tv.length; ti++) t[body(F(tv[ti], 'tag'))] = body(F(tv[ti], 'value'));
return t;
}
function consOf(o) { // 制約 (PRIMARY KEY / NOT NULL / FOREIGN KEY / DEFAULT:… / ALTERNATE KEY …) の文字列
var names = [], cs = listOf(F(o, 'constraint'));
for (var ci = 0; ci < cs.length; ci++) { var b = body(F(F(cs[ci], 'body'), 'body')) || nameOf(cs[ci]); if (b) names.push(b); }
return names;
}
function typeInto(at, tyName, mod) { // 型名 + jude.modifier ("10" / "10,2") → type / len / prec / scale
var t = String(tyName || '').toUpperCase(), m = /^\s*(\d+)\s*(?:,\s*(\d+))?/.exec(String(mod || ''));
at.type = t; at.len = ''; at.prec = ''; at.scale = '';
if (m) {
if (/^(DECIMAL|NUMERIC|NUMBER|DEC)$/.test(t)) { at.prec = m[1]; at.scale = m[2] || ''; }
else if (/CHAR|TEXT|CLOB|BINARY|BLOB|STRING|BIT|RAW|VARYING/.test(t)) at.len = m[1];
}
return at;
}
function uniq(map, nm, dup) { // 同名は _2 … を付ける
if (!map[nm]) { map[nm] = 1; return nm; }
var q = 2;
while (map[nm + '_' + q]) q++;
dup.push(nm); map[nm + '_' + q] = 1;
return nm + '_' + q;
}
// ドメイン (jude.type = er_Domain の UClassifierImp)
var domByName = {};
for (i = 0; i < objs.length; i++) {
if (cn(objs[i]) !== 'UClassifierImp') continue;
var dt = tagsOf(objs[i]);
if (dt['jude.type'] !== 'er_Domain') continue;
var dm = typeInto({ name: nameOf(objs[i]), pname: dt.alias3 || '', comment: body(F(objs[i], 'definition')) },
dt['jude.domain.datatype'], dt['jude.domain.modifier']);
if (!dm.name || domByName[dm.name]) continue;
domByName[dm.name] = dm; res.domains.push(dm);
}
// 要素の順序 = astah の構造ツリー (パッケージの ownedElementOwnership の順)、 そこに無いものはストリームの出現順
var tree = [], dupNames = [], pnames = {}, oi;
var TREE_KINDS = { EREntityImp: 1, ERRelationshipImp: 1, ERSubtypeRelationshipImp: 1, UERDiagramImp: 1 };
function take(o) { if (o && TREE_KINDS[cn(o)] && !o.tk) { o.tk = 1; tree.push(o); } }
for (i = 0; i < objs.length; i++) {
var own = listOf(F(objs[i], 'ownedElementOwnership'));
for (oi = 0; oi < own.length; oi++) take(F(own[oi], 'ownedElement'));
}
for (i = 0; i < objs.length; i++) take(objs[i]);
function ofKind() { var out = [], ki; for (ki = 0; ki < tree.length; ki++) for (var ai = 0; ai < arguments.length; ai++) if (cn(tree[ki]) === arguments[ai]) out.push(tree[ki]); return out; }
var ents = ofKind('EREntityImp');
for (i = 0; i < ents.length; i++) {
var ent = ents[i], tg = tagsOf(ent), ln = nameOf(ent), pn = tg.alias3 || ln;
if (!pn) continue;
var e = { pname: uniq(pnames, pn, dupNames), lname: ln, comment: body(F(ent, 'definition')), attrs: [], pos: {}, bkColor: '$FFFFFF' };
ent.ref = e;
var feats = listOf(F(ent, 'structuralFeature')), akeys = {};
for (k = 0; k < feats.length; k++) {
var a = feats[k];
if (cn(a) !== 'ERAttributeImp') continue;
var ta = tagsOf(a), an = nameOf(a), ap = ta.alias3 || an;
if (!ap) continue;
var at = { lname: an, pname: uniq(akeys, ap, []), domain: '', pk: false, fk: false, ak: false, notNull: false, def: '',
comment: body(F(a, 'definition')) };
var cons = consOf(a);
for (var ci2 = 0; ci2 < cons.length; ci2++) {
var cs0 = cons[ci2];
if (/^PRIMARY KEY/i.test(cs0)) at.pk = true;
else if (/^NOT NULL/i.test(cs0)) at.notNull = true;
else if (/^FOREIGN KEY/i.test(cs0)) at.fk = true;
else if (/^(ALTERNATE KEY|UNIQUE)/i.test(cs0)) at.ak = true;
else if (/^DEFAULT:/i.test(cs0)) at.def = cs0.substring(8).replace(/^\s+|\s+$/g, '');
}
if (F(a, 'referencedPrimaryKey')) at.fk = true;
if (at.pk) at.notNull = true;
// ★No.238: 既定値は制約 DEFAULT: の他に initialValue (UExpression.body) にもある。 書き出し (Field 6 番目) は defVal を見る
if (!at.def) { var ivb = body(F(F(a, 'initialValue'), 'body')); if (typeof ivb === 'string' && ivb.replace(/^\s+|\s+$/g, '')) at.def = ivb.replace(/^\s+|\s+$/g, ''); }
at.defVal = at.def || '';
var ty = F(a, 'type'), tt = tagsOf(ty);
if (ty && tt['jude.type'] === 'er_Domain') {
at.domain = nameOf(ty);
typeInto(at, tt['jude.domain.datatype'], tt['jude.domain.modifier']);
if (!domByName[at.domain]) res.warnings.push(e.pname + '.' + at.pname + ': ドメイン「' + at.domain + '」の定義が見つかりません');
} else {
typeInto(at, nameOf(ty), ta['jude.modifier']);
}
a.ref = { e: e, at: at };
e.attrs.push(at);
}
// ★No.238: ユニーク索引 / 索引 (EREntityImp.erIndexes の ERIndexImp: 属性の参照の列挙 + ユニークの旗) → A5M2 の IndexInfo。 ユニーク索引の属性は代替キー (AK)
var exs = listOf(F(ent, 'erIndexes')), ixn = 0;
for (k = 0; k < exs.length; k++) {
var ixo = exs[k], ixCols = [], ixf = (ixo && ixo.f) ? ixo.f : {}, fk2;
for (fk2 in ixf) {
if (!ixf.hasOwnProperty(fk2) || !ixf[fk2] || !ixf[fk2].list) continue;
var il = ixf[fk2].list;
for (var ii = 0; ii < il.length; ii++) if (il[ii] && cn(il[ii]) === 'ERAttributeImp' && il[ii].ref && il[ii].ref.e === e) ixCols.push(il[ii].ref.at);
}
if (!ixCols.length) continue;
var allPk = true;
for (var ipk = 0; ipk < ixCols.length; ipk++) if (!ixCols[ipk].pk) allPk = false;
if (allPk) continue; // 主キーの索引 (isKey) は A5M2 の主キーで表す
ixn++;
var uq = F(ixo, 'unique'); if (uq == null) uq = F(ixo, 'isUnique'); if (uq == null) uq = F(ixo, 'uniqueness');
var isUq = (uq === true || String(uq) === 'true' || String(uq) === '1');
if (!e.indexes) e.indexes = [];
e.indexes.push({ name: nameOf(ixo) || ('IX' + ixn), unique: isUq, cols: ixCols.map(function (c0) { return c0.pname; }) });
if (isUq) for (var iu = 0; iu < ixCols.length; iu++) ixCols[iu].ak = true;
}
res.entities.push(e);
}
// リレーション: FK 属性 (foreignKeys) の持ち主 = 子、 参照先の主キー (referencedPrimaryKey) の持ち主 = 親。
// サブタイプ (ERSubtypeRelationshipImp) は A5M2 の [Subtype] ノード (記号) に集約する: スーパータイプ + group ごとに 1 ノード、
// 親 → 記号 → 各サブタイプの関連は書き出し側 (_a5erWriteModel) が作る。 conclusive → CompleteCategory、 判別属性名 → 親→記号のキャプション
var nodeByKey = {}, noFkRels = 0, noFkSubs = 0;
function fkPair(fk) {
var pkA = F(fk, 'referencedPrimaryKey');
if (!fk || !fk.ref || !pkA || !pkA.ref) return null;
return { c: fk.ref, p: pkA.ref };
}
function multRt(end) { // 端の多重度 → A5M2 RelationType ('' = 不明 → 既定のまま)。 ★No.233: 定数 (lower = upper >= 2) は 5 + 個数 (Cardinarity)
var mu = end && F(end, 'multiplicity'), rg = mu && listOf(F(mu, 'multiplicityRange'));
if (!rg || !rg.length || !rg[0] || !rg[0].f) return { rt: '', card: '' };
var lo = F(rg[0], 'lower'), up = F(rg[0], 'upper');
if (lo === 0 && up === 1) return { rt: '1', card: '' };
if (lo === 1 && up === 1) return { rt: '2', card: '' };
if (lo === 0 && up === -1) return { rt: '3', card: '' };
if (lo === 1 && up === -1) return { rt: '4', card: '' };
if (typeof lo === 'number' && lo === up && lo >= 2) return { rt: '5', card: String(lo) };
return { rt: '', card: '' };
}
var rels = ofKind('ERRelationshipImp', 'ERSubtypeRelationshipImp');
for (i = 0; i < rels.length; i++) {
var ro = rels[i], rk = cn(ro);
var sub = rk === 'ERSubtypeRelationshipImp', fks = listOf(F(ro, sub ? 'subTypeForeignKeys' : 'foreignKeys'));
var r = { parent: '', child: '', parentCols: [], childCols: [], dep: sub ? true : !!F(ro, 'isIdentifying'), rt1: '2', rt2: sub ? '1' : '3',
caption: '', pname: '', pages: [] }, nullable = 0, pe = null, ce = null; // ★No.234: 通常の関連の Caption は動詞句だけ (下)。 astah の図は論理名を描かない
if (sub) {
var supE = F(ro, 'supertype'), subE = F(ro, 'subtype');
pe = supE && supE.ref && supE.ref.pname ? supE.ref : null; ce = subE && subE.ref && subE.ref.pname ? subE.ref : null;
var disc = F(ro, 'discriminatorAttribute');
if (!r.caption && disc && disc.ref) r.caption = disc.ref.at.lname;
}
for (k = 0; k < fks.length; k++) {
var pr = fkPair(fks[k]);
if (!pr) { res.warnings.push((nameOf(ro) || rk) + ': FK 属性 ' + nameOf(fks[k]) + ' の参照先 (親の主キー) が見つかりません'); continue; }
if (!ce) ce = pr.c.e;
if (!pe) pe = pr.p.e;
if (pr.c.e !== ce || pr.p.e !== pe) continue;
r.childCols.push(pr.c.at.pname); r.parentCols.push(pr.p.at.pname);
if (!pr.c.at.notNull) nullable++;
}
if (!pe || !ce) { // FK 属性が無い (親に主キーが無い等) → 図の線 ERRelationshipPresentation.servers = [親の図形, 子の図形] から親子を引く
var prs0 = listOf(F(ro, 'presentation'));
for (k = 0; k < prs0.length && (!pe || !ce); k++) {
var sv0 = listOf(F(prs0[k], 'servers'));
if (sv0.length < 2) continue;
var m0 = F(sv0[0], 'model'), m1 = F(sv0[1], 'model');
if (!pe && m0 && m0.ref && m0.ref.pname) pe = m0.ref;
if (!ce && m1 && m1.ref && m1.ref.pname) ce = m1.ref;
}
}
if (!pe || !ce) { res.warnings.push((nameOf(ro) || rk) + ': 親または子のエンティティが見つかりません (省略)'); continue; }
if (!r.childCols.length) {
// ★Ver1.0.11: FK 属性の無いサブタイプ (子が主キーを継承しない = 属性の無い箱) も省略せず、 記号→子の項目なしの線として残す。
// 省略すると子は「属性が無く他とつながらない箱」= 見出し扱いになってコメントに化けた (ユーザー報告 2026-09-25: 従業員 → 正社員 等)
if (sub) noFkSubs++;
else noFkRels++; // 通常のリレーションシップは線だけで残す (A5M2 は Fields が空でも線を描く)
}
r.parent = pe.pname; r.child = ce.pname;
if (nullable) r.rt1 = '1';
// ★No.180: 関連の端 (connection = [ERRelationshipEndImp ×2]) の多重度 (UMultiplicity.multiplicityRange の lower..upper) を A5M2 の
// RelationType に写す: 0..1 → 1 (0または1、 親側なら ◇) / 1..1 → 2 (1) / 0..* → 3 (0以上) / 1..* → 4 (1以上)。 端は type (エンティティ) で親子を見分ける
// (FK 属性の無い関連 = 主キーの無い親 / 多対多 は FK の NULL 可否から多重度を引けないので、 これが唯一の手掛かり)。
// ★端の multiplicity / type は親クラス UStructuralFeatureImp 側に入っている (_astaDeser の同名フィールドの扱いを参照)
if (!sub) {
var ends = listOf(F(ro, 'connection')), pEnd = null, cEnd = null;
for (k = 0; k < ends.length; k++) {
var et = F(ends[k], 'type'), ee = et && et.ref && et.ref.pname ? et.ref : null;
if (ee === pe && !pEnd) pEnd = ends[k];
else if (ee === ce && !cEnd) cEnd = ends[k];
}
if (!pEnd && !cEnd && ends.length === 2) { pEnd = ends[0]; cEnd = ends[1]; }
var pRt = multRt(pEnd), cRt = multRt(cEnd);
if (pRt.rt) { r.rt1 = pRt.rt; if (pRt.card) r.card1 = pRt.card; }
if (cRt.rt) { r.rt2 = cRt.rt; if (cRt.card) r.card2 = cRt.card; }
// ★No.234: astah の ER 図は線の横に動詞句 (親側 / 子側 = 関連の端の名前) を出し、 リレーションシップの論理名は出さない
// → OBER (No.228) と同じ「親から子 / 子から親」を Caption に。 動詞句が無ければ空 (論理名は出さない)
var pVerb = nameOf(pEnd), cVerb = nameOf(cEnd);
r.caption = pVerb + (cVerb ? (pVerb ? ' / ' : '') + cVerb : '');
}
if (sub) {
var grp = F(ro, 'group') || 0, gkey = pe.pname + '#' + grp, node = nodeByKey[gkey];
if (!node) {
node = { pname: uniq(pnames, 'SUBTYPE_' + pe.pname + (grp ? '_' + grp : ''), []), parent: pe.pname, complete: !!F(ro, 'conclusive'),
shared: false, caption: r.caption, pos: {}, subs: [] };
nodeByKey[gkey] = node; res.subtypes.push(node);
}
var link = { child: ce.pname, parentCols: r.parentCols, childCols: r.childCols, pages: [] };
node.subs.push(link);
ro.ref = { node: node, link: link };
continue;
}
ro.ref = r;
res.relations.push(r);
}
// ER 図 = ページ、 EREntityPresentation = 配置 (location / width / height / baseColor)、 線のプレゼンテーションでリレーションのページ
var pageNames = {}, dias = ofKind('UERDiagramImp');
for (i = 0; i < dias.length; i++) {
if (i === 0 && /IDEF1X/i.test(String(F(dias[i], 'notation') || ''))) res.viewFormat = '1'; // 最初の ER 図の表記を A5M2 の ViewFormat に
res.nonDepDash = true; // ★No.240: astah の IE 表示は依存 = 実線 / 非依存 = 破線 → A5M2 の UseNondependenceDashLine=1 (OBER の No.230 と同じ)
var pgn = uniq(pageNames, nameOf(dias[i]) || ('ER図' + (res.pages.length + 1)), []);
dias[i].ref = { name: pgn, entities: 0, relations: 0 };
res.pages.push(dias[i].ref);
}
for (i = 0; i < objs.length; i++) {
var pres = objs[i], pk2 = cn(pres);
if (pk2 === 'NotePresentation' || pk2 === 'NoteAnchorPresentation') {
// ★No.235: astah のノート (付箋。 model = UCommentImp の body) → A5M2 の [Comment]、 ノートからの線 (NoteAnchorPresentation。 両端 = allPoints) → 破線の [Line]
var dgN = F(pres, 'diagram');
if (!dgN || !dgN.ref || !dgN.ref.name) continue;
var zN = -(Number(F(pres, 'depth')) || 0), styN = styleOf(pres);
if (pk2 === 'NotePresentation') {
var locN = F(pres, 'location'), noteTxt = body(F(pres, 'model'));
if (typeof noteTxt !== 'string' || !noteTxt) { var lbN = F(pres, 'label'); noteTxt = typeof lbN === 'string' ? lbN : ''; }
var fpxN = parseFloat(styN['font.size']);
res.comments.push({ page: dgN.ref.name, x: F(locN, 'x') || 0, y: F(locN, 'y') || 0, w: F(pres, 'width') || 0, h: F(pres, 'height') || 0,
text: noteTxt, bkColor: styN['fill.color'] || '', lineColor: styN['line.color'] || '', fontColor: styN['font.color'] || '',
fontSize: fpxN > 0 ? Math.round(fpxN * 0.75) : 0, z: zN });
} else {
var apN = F(pres, 'outerPoints') || F(pres, 'allPoints'), ptsN = (apN && apN.array) ? apN.array : []; // outerPoints = 箱の辺で切った両端
if (ptsN.length >= 2) {
var p0 = ptsN[0], pN = ptsN[ptsN.length - 1];
res.lines.push({ page: dgN.ref.name, x: F(p0, 'x') || 0, y: F(p0, 'y') || 0, w: (F(pN, 'x') || 0) - (F(p0, 'x') || 0), h: (F(pN, 'y') || 0) - (F(p0, 'y') || 0),
lineColor: styN['line.color'] || '', lineWidth: styN['line.width'] || '', lineType: 2, z: zN });
}
}
continue;
}
if (pk2 === 'TextPresentation' || pk2 === 'RectPresentation' || pk2 === 'LinePresentation') {
// 図上の注記 / 矩形 / 直線 (モデル要素を持たない図形) → A5M2 の [Comment] / [Shape] / [Line]。 色は styleMap (#RRGGBB)
var dgA = F(pres, 'diagram');
if (!dgA || !dgA.ref || !dgA.ref.name) continue;
var locA = F(pres, 'location'), ax = F(locA, 'x') || 0, ay = F(locA, 'y') || 0, sty = styleOf(pres);
// ★Ver1.0.22 (No.199): astah の depth は小さいほど手前 (-1 = 最背面 … -N = 最前面) → A5M2 の ZOrder (大きいほど手前) に写す
var zA = -(Number(F(pres, 'depth')) || 0);
if (pk2 === 'LinePresentation') {
var mv = F(pres, 'localMovement'); // 直線は始点 location + 終点までのベクトル localMovement
res.lines.push({ page: dgA.ref.name, x: ax, y: ay, w: (mv && F(mv, 'x')) || 0, h: (mv && F(mv, 'y')) || 0,
lineColor: sty['line.color'] || '', lineWidth: sty['line.width'] || '', z: zA });
} else if (pk2 === 'RectPresentation') {
res.shapes.push({ page: dgA.ref.name, x: ax, y: ay, w: F(pres, 'width') || 0, h: F(pres, 'height') || 0, shapeType: 'Rectangle',
lineColor: sty['line.color'] || '', brushColor: sty['fill.color'] || '', lineWidth: sty['line.width'] || '', z: zA });
} else {
var txt = F(pres, 'text'); if (typeof txt !== 'string') txt = F(pres, 'label');
var fpx = parseFloat(sty['font.size']); // astah の文字サイズ (px) → A5M2 の FontSize (pt)。 描画側が元の比率で描く
if (String(sty['shape'] || '') !== 'border_rect') {
// ★No.236: 枠・背景の無いテキスト (shape が border_rect 以外) → A5M2 の [Shape] (線無し LineType=1、 塗り透明 BrushAlpha=0、 Text、 文字色 FontColor)
res.shapes.push({ page: dgA.ref.name, x: ax, y: ay, w: F(pres, 'width') || 0, h: F(pres, 'height') || 0, shapeType: 'Rectangle',
text: typeof txt === 'string' ? txt : '', lineType: 1, brushAlpha: 0, lineColor: '', brushColor: '',
fontColor: sty['font.color'] || '', fontSize: fpx > 0 ? Math.round(fpx * 0.75) : 0,
fontBold: /BOLD/i.test(String(sty['font.style'] || '')), z: zA });
continue;
}
res.comments.push({ page: dgA.ref.name, x: ax, y: ay, w: F(pres, 'width') || 0, h: F(pres, 'height') || 0,
text: typeof txt === 'string' ? txt : '', bkColor: sty['fill.color'] || '', lineColor: sty['line.color'] || '',
fontColor: sty['font.color'] || '', fontSize: fpx > 0 ? Math.round(fpx * 0.75) : 9, z: zA });
}
continue;
}
if (pk2 !== 'EREntityPresentation' && pk2 !== 'ERRelationshipPresentation' && pk2 !== 'ERSubtypeRelationshipPresentation') continue;
var md = F(pres, 'model'), dg = F(pres, 'diagram');
if (!md || !md.ref || !dg || !dg.ref || !dg.ref.name) continue;
if (pk2 === 'EREntityPresentation') {
if (!md.ref.pname) continue;
var loc = F(pres, 'location');
md.ref.pos[dg.ref.name] = { x: Math.max(0, F(loc, 'x') || 0), y: Math.max(0, F(loc, 'y') || 0),
w: Math.max(40, F(pres, 'width') || 0), h: Math.max(30, F(pres, 'height') || 0),
z: -(Number(F(pres, 'depth')) || 0) }; // 見出し箱 (コメント化) の重なり順に使う (No.199)
var col = F(pres, 'baseColor'), fc;
if (col && typeof F(col, 'value') === 'number') md.ref.bkColor = _astaColor(F(col, 'value'));
// ★Ver1.0.12 (No.176): 実物の astah は baseColor を持たず styleMap の fill.color ('#RRGGBB') に背景色を持つ (既定は白)
else if ((fc = /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(String(styleOf(pres)['fill.color'] || ''))))
md.ref.bkColor = ('$' + fc[3] + fc[2] + fc[1]).toUpperCase();
dg.ref.entities++;
} else if (md.ref.node) {
// サブタイプの線: 記号の位置は servers にある ERSubtypeRelationshipGroupPresentation の location (線の合流点)
var nd = md.ref.node, lk = md.ref.link, pgn2 = dg.ref.name, svs = listOf(F(pres, 'servers')), gp = null;
if (lk.pages.indexOf(pgn2) < 0) { lk.pages.push(pgn2); dg.ref.relations++; }
for (k = 0; k < svs.length; k++) if (cn(svs[k]) === 'ERSubtypeRelationshipGroupPresentation') gp = svs[k];
var gl = gp ? F(gp, 'location') : null;
if (!nd.pos[pgn2] && gl && typeof F(gl, 'x') === 'number') nd.pos[pgn2] = { x: F(gl, 'x') - SUB_W / 2, y: F(gl, 'y') - SUB_H / 2, w: SUB_W, h: SUB_H };
} else if (md.ref.parent) {
var already = false;
for (k = 0; k < md.ref.pages.length; k++) if (md.ref.pages[k] === dg.ref.name) already = true;
if (!already) { md.ref.pages.push(dg.ref.name); dg.ref.relations++; }
// ★No.237: 線の経路 (outerPoints = 親の辺の点, 折れ点…, 子の辺の点。 図の px。 ★allPoints の両端は端子が中央のとき箱の中心なので使わない)
// → 書き出し側が端子の位置 (線位置1 / 3) + 自由結線 / 直線にする (OBER の No.227 と同じ構造)
var apR = F(pres, 'outerPoints') || F(pres, 'allPoints'), ptsR = (apR && apR.array) ? apR.array : [], rpts = [];
for (k = 0; k < ptsR.length; k++) if (ptsR[k] && typeof F(ptsR[k], 'x') === 'number') rpts.push({ x: F(ptsR[k], 'x'), y: F(ptsR[k], 'y') });
if (rpts.length >= 2 && !(md.ref.routes && md.ref.routes[dg.ref.name])) { if (!md.ref.routes) md.ref.routes = {}; md.ref.routes[dg.ref.name] = { pts: rpts }; }
}
}
// 見出しだけのエンティティ (ユーザー指摘 2026-09-23): 属性が無く、 属性のあるエンティティと (関連の連鎖でも) つながらない箱は
// 図の見出し (「リファレンス」「イベント」等) なので [Comment] にする (名前が空なら色付きの [Shape])。 エンティティとしては出さない。
// ★属性の無いエンティティでも、 属性のあるエンティティと関連で結ばれていれば本物 (作業中の箱) として残す
var labelEntities = [], realSet = {}, ci2, changed = true;
for (ci2 = 0; ci2 < res.entities.length; ci2++) if (res.entities[ci2].attrs.length) realSet[res.entities[ci2].pname] = 1;
function relEnds() { // 関連の両端 (通常 + サブタイプの親子)
var out = [], q;
for (q = 0; q < res.relations.length; q++) out.push([res.relations[q].parent, res.relations[q].child]);
for (q = 0; q < res.subtypes.length; q++) for (var q2 = 0; q2 < res.subtypes[q].subs.length; q2++) out.push([res.subtypes[q].parent, res.subtypes[q].subs[q2].child]);
return out;
}
var ends = relEnds();
while (changed) { // 本物とつながる箱は本物 (連鎖)
changed = false;
for (ci2 = 0; ci2 < ends.length; ci2++) {
var ea = ends[ci2][0], eb = ends[ci2][1];
if (realSet[ea] && !realSet[eb]) { realSet[eb] = 1; changed = true; }
if (realSet[eb] && !realSet[ea]) { realSet[ea] = 1; changed = true; }
}
}
var keptEnts = [];
for (ci2 = 0; ci2 < res.entities.length; ci2++) {
var le = res.entities[ci2];
if (realSet[le.pname]) { keptEnts.push(le); continue; }
labelEntities.push(le);
for (var lp in le.pos) if (le.pos.hasOwnProperty(lp)) {
var lpos = le.pos[lp], lnm = String(le.lname || '').replace(/[\s\u3000]+/g, '');
for (var lpg = 0; lpg < res.pages.length; lpg++) if (res.pages[lpg].name === lp && res.pages[lpg].entities > 0) res.pages[lpg].entities--; // \u56f3\u306e\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u6570\u304b\u3089\u3082\u5916\u3059
if (lnm) res.comments.push({ page: lp, x: lpos.x, y: lpos.y, w: lpos.w, h: lpos.h, text: le.lname, bkColor: le.bkColor || '', lineColor: '', fontSize: 9, z: lpos.z });
else res.shapes.push({ page: lp, x: lpos.x, y: lpos.y, w: lpos.w, h: lpos.h, shapeType: 'Rectangle', lineColor: '', brushColor: le.bkColor || '', lineWidth: '', z: lpos.z });
}
}
if (labelEntities.length) {
res.entities = keptEnts;
var labelSet = {}, ln2;
for (ci2 = 0; ci2 < labelEntities.length; ci2++) labelSet[labelEntities[ci2].pname] = 1;
var keptRels = [];
for (ci2 = 0; ci2 < res.relations.length; ci2++) if (!labelSet[res.relations[ci2].parent] && !labelSet[res.relations[ci2].child]) keptRels.push(res.relations[ci2]);
res.relations = keptRels;
var lnames = [];
for (ci2 = 0; ci2 < labelEntities.length; ci2++) { ln2 = String(labelEntities[ci2].lname || '').replace(/[\s\u3000]+/g, ''); lnames.push(ln2 || '(名前なし)'); }
res.warnings.push(labelEntities.length + ' 件のエンティティは属性が無く他のエンティティとつながらないため図の見出し (コメント) として扱いました: ' + lnames.join(', '));
}
// 集計と警告
res.stats.tables = res.entities.length;
for (i = 0; i < res.entities.length; i++) res.stats.columns += res.entities[i].attrs.length;
res.stats.fks = res.relations.length; res.stats.pages = res.pages.length; res.stats.domains = res.domains.length;
res.stats.subtypes = res.subtypes.length;
res.stats.annotations = res.comments.length + res.shapes.length + res.lines.length;
if (noFkRels) res.warnings.push(noFkRels + ' 本のリレーションシップは FK 属性が無い (親に主キーが無い等) ため、 項目なしの線だけを出力しました');
if (noFkSubs) res.warnings.push(noFkSubs + ' 本のサブタイプ関係は子に FK 属性が無いため、 サブタイプ記号から子への項目なしの線だけを出力しました');
for (i = 0; i < res.subtypes.length; i++) res.stats.fks += 1 + res.subtypes[i].subs.length; // 親→記号 + 記号→各サブタイプ = .a5er の [Relation] 数
if (dupNames.length) res.warnings.push('同じ物理名のエンティティが複数あるため _2 … を付けた: ' + dupNames.join(', '));
return res;
}
function _a5erWriteModel(model) {
var pages = [], pageMax = {}, pi, PX = model.px || _OBER_PX; // px = モデル座標 → 0.1 mm の倍率 (OBER は 2.65、 Visio は 1 = 変換済み)
var entByName = {}, ebi; // No.227: 線の経路の端子を箱の辺に当てる
for (ebi = 0; ebi < (model.entities || []).length; ebi++) entByName[model.entities[ebi].pname] = model.entities[ebi];
for (pi = 0; pi < model.pages.length; pi++) { pages.push(model.pages[pi].name); pageMax[model.pages[pi].name] = { x: 0, y: 0 }; }
var UNPLACED = '(未配置)', ux = 100, uy = 100, ucol = 0, unplaced = 0;
for (var ei = 0; ei < model.entities.length; ei++) {
var e = model.entities[ei], any = false;
for (var pn in e.pos) if (e.pos.hasOwnProperty(pn)) {
any = true;
var p = e.pos[pn];
p.X = Math.round(p.x * PX); p.Y = Math.round(p.y * PX); p.W = Math.round(p.w * PX); p.H = Math.round(p.h * PX);
if (!pageMax[pn]) { pages.push(pn); pageMax[pn] = { x: 0, y: 0 }; }
if (p.X + p.W > pageMax[pn].x) pageMax[pn].x = p.X + p.W;
if (p.Y + p.H > pageMax[pn].y) pageMax[pn].y = p.Y + p.H;
}
if (!any) {
if (!pageMax[UNPLACED]) { pages.push(UNPLACED); pageMax[UNPLACED] = { x: 0, y: 0 }; }
var h0 = 70 + 36 * Math.max(1, e.attrs.length) + 30;
e.pos[UNPLACED] = { X: ux, Y: uy, W: 400, H: h0 };
unplaced++;
if (ux + 400 > pageMax[UNPLACED].x) pageMax[UNPLACED].x = ux + 400;
if (uy + h0 > pageMax[UNPLACED].y) pageMax[UNPLACED].y = uy + h0;
if (++ucol >= 5) { ucol = 0; ux = 100; uy += h0 + 100; } else ux += 500;
}
}
if (unplaced) model.warnings.push(unplaced + ' 件のエンティティはどのビューにも無いため「' + UNPLACED + '」ページに置きました');
var annAll = (model.shapes || []).concat(model.lines || [], model.comments || []); // 図上の注記・矩形・直線も用紙の大きさに入れる
for (var ax0 = 0; ax0 < annAll.length; ax0++) {
var an0 = annAll[ax0], aX = Math.round(an0.x * PX) + Math.max(0, Math.round(an0.w * PX)), aY = Math.round(an0.y * PX) + Math.max(0, Math.round(an0.h * PX));
if (!pageMax[an0.page]) { pages.push(an0.page); pageMax[an0.page] = { x: 0, y: 0 }; }
if (aX > pageMax[an0.page].x) pageMax[an0.page].x = aX;
if (aY > pageMax[an0.page].y) pageMax[an0.page].y = aY;
}
// サブタイプのノード (A5M2 の [Subtype] = 記号 72×50)。 位置が無いページは親の真下と子の上端の中間 (描画器は記号の上下で親子を見分ける)
var subs = model.subtypes || [], si, q2;
function entOf(nm) { for (q2 = 0; q2 < model.entities.length; q2++) if (model.entities[q2].pname === nm) return model.entities[q2]; return null; }
for (si = 0; si < subs.length; si++) {
var nd = subs[si], pe0 = entOf(nd.parent), pn2;
for (pn2 in nd.pos) if (nd.pos.hasOwnProperty(pn2)) {
var np = nd.pos[pn2];
np.X = Math.round(np.x * PX); np.Y = Math.round(np.y * PX); np.W = Math.round(np.w * PX); np.H = Math.round(np.h * PX);
if (!pageMax[pn2]) { pages.push(pn2); pageMax[pn2] = { x: 0, y: 0 }; }
}
for (pi = 0; pi < pages.length; pi++) {
var pgn3 = pages[pi];
if (nd.pos[pgn3] || !pe0 || !pe0.pos[pgn3]) continue;
var pp0 = pe0.pos[pgn3], minTop = null;
for (var q3 = 0; q3 < nd.subs.length; q3++) {
var ce0 = entOf(nd.subs[q3].child);
if (ce0 && ce0.pos[pgn3] && (minTop == null || ce0.pos[pgn3].Y < minTop)) minTop = ce0.pos[pgn3].Y;
}
if (minTop == null) continue;
nd.pos[pgn3] = { X: Math.round(pp0.X + pp0.W / 2 - 36), Y: Math.round((pp0.Y + pp0.H + minTop) / 2 - 25), W: 72, H: 50 };
}
}
var paperOf = {};
for (pi = 0; pi < pages.length; pi++) paperOf[pages[pi]] = _a5erPickPaper(pageMax[pages[pi]].x, pageMax[pages[pi]].y).nm;
var stamp = _a5erTimestamp(), L = [];
L.push('# A5:ER FORMAT:21');
L.push('# A5:ER ENCODING:UTF8');
L.push('# A5:ER Mk-1 Copyright © 2007 m.matsubara');
L.push('# A5:SQL Mk-2 Generated by Commonweal EDM converter (' + (model.kind || '') + ')');
L.push('# https://a5m2.mmatsubara.com');
L.push('');
L.push('[Manager]');
L.push('ProjectName=' + _a5erLine(model.name || ''));
L.push('Author=');
L.push('MaxEntityRowShow=1000');
L.push('ReadOnlyRecommend=0');
for (pi = 0; pi < pages.length; pi++) L.push('PageInfo="' + _a5erStr(pages[pi]) + '",3,"' + paperOf[pages[pi]] + '",$FFFFFF');
// ドメイン → DomainInfo="名前","型(桁)","コメント (OBER の定義内容)","既定物理名"。 属性側は型欄を *名前 にする (Ver1.0.5)
var doms = model.domains || [];
for (var dmi = 0; dmi < doms.length; dmi++) {
L.push('DomainInfo="' + _a5erStr(doms[dmi].name) + '","' + _a5erStr(_a5erType(doms[dmi])) + '","' +
_a5erStr(doms[dmi].comment || '') + '","' + _a5erStr(doms[dmi].pname || '') + '"');
}
L.push('LogicalView=1');
L.push('DecodeDomain=0');
L.push('ViewFormat=' + (model.viewFormat === '1' ? '1' : '0')); // 0=IE / 1=IDEF1X (astah の ER 図の表記を保つ)
L.push('UseNondependenceDashLine=' + (model.nonDepDash ? '1' : '0')); // ★No.230: OBER の IE 表示 (非依存 = 破線) を A5M2 のオプションで保つ
L.push('FontName=Tahoma');
L.push('FontSize=9');
L.push('PaperSize=' + paperOf[pages[0]]);
L.push('ShowPageoutRelation=1');
L.push('DefaultPkName=%0:s_PKC');
L.push('DefaultPkIndexName=%0:s_PKI');
L.push('DefaultIndexName=%0:s_IX%1:d');
L.push('DefaultFkName=%0:s_FK%1:d');
L.push('SqlSeparator=0');
L.push('UpperCaseKeyword=0');
L.push('ShowTag=1');
L.push('ShowCommonAttributes=0');
L.push('ShowDisableAttributes=0');
L.push('BugFixEntityWidth=1');
L.push('');
for (var ti = 0; ti < model.entities.length; ti++) {
var t = model.entities[ti], first = null;
for (var pk0 in t.pos) if (t.pos.hasOwnProperty(pk0)) { first = t.pos[pk0]; break; }
L.push('[Entity]');
L.push('PName=' + _a5erLine(t.pname));
L.push('LName=' + _a5erLine(t.lname || t.pname));
L.push('Comment=' + _a5erStr(t.comment || ''));
L.push('TableInnerOption=');
L.push('TableOption=');
L.push('Page=MAIN');
L.push('Left=' + (first ? first.X : 0));
L.push('Top=' + (first ? first.Y : 0));
var pkOrder = 0;
for (var ci = 0; ci < t.attrs.length; ci++) {
var c = t.attrs[ci];
L.push('Field="' + _a5erStr(c.lname || c.pname) + '","' + _a5erStr(c.pname) + '","' +
_a5erStr(c.domain ? ('*' + c.domain) : (c.type ? _a5erType(c) : '')) + '","' + // 型が無い (Visio 等) は空。 VARCHAR2 の既定値は物理 DB からの ER 図だけ
(c.notNull ? 'NOT NULL' : '') + '",' + (c.pk ? String(pkOrder++) : '') + ',"' + _a5erStr(c.defVal || '') + '","' + _a5erStr(c.comment || '') + '",$FFFFFFFF,""'); // ★No.229: 既定値 (6 番目) / コメント (7 番目、 2026-10-02 訂正)
}
// ★No.229: ユニーク索引 / 索引 (OBER の INDEX I-TYPE 1 / 2)。 A5M2 の IndexInfo="名前",ユニーク(1/0),"列,列",""
var tix = t.indexes || [];
for (var ixi = 0; ixi < tix.length; ixi++) if (tix[ixi].cols && tix[ixi].cols.length) {
L.push('IndexInfo="' + _a5erStr(tix[ixi].name) + '",' + (tix[ixi].unique ? '1' : '0') + ',"' + tix[ixi].cols.join(',') + '",""');
}
L.push('EffectMode=None');
L.push('Color=$000000');
L.push('BkColor=' + (t.bkColor || '$FFFFFF'));
L.push('ModifiedDateTime=' + stamp);
for (pi = 0; pi < pages.length; pi++) {
var pp = t.pos[pages[pi]];
if (pp) L.push('Position="' + _a5erStr(pages[pi]) + '",' + pp.X + ',' + pp.Y + ',' + pp.W + ',' + pp.H);
}
L.push('ZOrder=' + (ti + 1));
L.push('');
}
// [Subtype] ノード + 親→記号 (項目なし) / 記号→各サブタイプ (FK の項目) の関連
var rels = model.relations.slice();
for (si = 0; si < subs.length; si++) {
var nd2 = subs[si], npages = [];
L.push('[Subtype]');
L.push('PName=' + _a5erLine(nd2.pname));
L.push('SharedMode=' + (nd2.shared ? '1' : '0'));
L.push('CompleteCategory=' + (nd2.complete ? '1' : '0'));
for (pi = 0; pi < pages.length; pi++) {
var sp = nd2.pos[pages[pi]];
if (sp) { L.push('Position="' + _a5erStr(pages[pi]) + '",' + sp.X + ',' + sp.Y + ',' + sp.W + ',' + sp.H); npages.push(pages[pi]); }
}
L.push('ZOrder=' + (model.entities.length + si + 1));
L.push('');
rels.push({ parent: nd2.parent, child: nd2.pname, parentCols: [], childCols: [], rt1: '1', rt2: '3', dep: false, caption: nd2.caption || '', pname: '', pages: npages });
for (var li = 0; li < nd2.subs.length; li++) {
var lk2 = nd2.subs[li], lpages = [], ce1 = entOf(lk2.child);
for (pi = 0; pi < npages.length; pi++) if (ce1 && ce1.pos[npages[pi]]) lpages.push(npages[pi]);
rels.push({ parent: nd2.pname, child: lk2.child, parentCols: lk2.parentCols, childCols: lk2.childCols, rt1: '1', rt2: '3', dep: false, caption: '', pname: '', pages: lpages });
}
}
for (var ri = 0; ri < rels.length; ri++) {
var r = rels[ri];
L.push('[Relation]');
L.push('Entity1=' + _a5erLine(r.parent));
L.push('Entity2=' + _a5erLine(r.child));
L.push('RelationType1=' + (r.rt1 || '2'));
L.push('RelationType2=' + (r.rt2 || '3'));
L.push('Fields1=' + r.parentCols.join(','));
L.push('Fields2=' + r.childCols.join(','));
L.push('Cardinarity1=' + ((r.rt1 === '5' && r.card1) ? r.card1 : '')); // ★No.233: 親側の定数 (astah の多重度 n..n)
L.push('Cardinarity2=' + ((r.rt2 === '5' && r.card2) ? r.card2 : '')); // ★No.223: 定数 (N 個固定) の個数
var rpages = r.pages && r.pages.length ? r.pages : [];
if (!rpages.length) { // ビューに線が無ければ 両端が居るページ全部
var pe = null, ce = null;
for (var q = 0; q < model.entities.length; q++) { if (model.entities[q].pname === r.parent) pe = model.entities[q]; if (model.entities[q].pname === r.child) ce = model.entities[q]; }
for (pi = 0; pi < pages.length; pi++) if (pe && ce && pe.pos[pages[pi]] && ce.pos[pages[pi]]) rpages.push(pages[pi]);
}
// ★No.227: ビューの線の経路 (r.routes[ページ] = 端子と折れ点、 モデル座標) → 端子の位置 (線位置1 / 3 = 辺に沿った比率) と
// 自由結線 (ラインモード 10、 頂点 = 折れ点を 0.1 mm に)。 折れ点が無い / 一直線なら自動 (0) で端子の位置だけ
var rmode0 = 0;
var relPosLine = function (pg) { // ★Nashorn (strict) はブロック内の関数宣言を許さない → 関数式
var rt = r.routes && r.routes[pg], pe = entByName[r.parent], ce = entByName[r.child];
var ptsR = rt && rt.pts ? rt.pts.slice(0) : (rt && rt.length ? rt.slice(0) : []);
if (ptsR.length < 2 || !pe || !ce || !pe.pos[pg] || !ce.pos[pg]) return '0,5000,5000,5000,R,R,""';
var P = pe.pos[pg], C = ce.pos[pg], k, pa = rt.pa, ca = rt.ca;
function distRect(p, b) { return Math.max(b.x - p.x, 0, p.x - (b.x + b.w)) + Math.max(b.y - p.y, 0, p.y - (b.y + b.h)); }
if (distRect(ptsR[0], P) > distRect(ptsR[0], C) && distRect(ptsR[ptsR.length - 1], P) < distRect(ptsR[ptsR.length - 1], C)) { ptsR.reverse(); var sw = pa; pa = ca; ca = sw; }
// 端子: ANCHOR の辺 (無ければ最も近い辺) への射影。 点がその辺に乗っていなければ折れ点として残す (OBER は最後の区間を暗黙に描く)
function termOf(p, b, anchor) {
var side = { '0': 'L', '1': 'T', '2': 'R', '3': 'B' }[String(anchor == null ? '' : anchor)] || null;
var dl = Math.abs(p.x - b.x), dr = Math.abs(p.x - (b.x + b.w)), dt = Math.abs(p.y - b.y), db = Math.abs(p.y - (b.y + b.h));
if (!side) { var mn = Math.min(dl, dr, dt, db); side = mn === dl ? 'L' : mn === dr ? 'R' : mn === dt ? 'T' : 'B'; }
var f = (side === 'L' || side === 'R') ? (p.y - b.y) / (b.h || 1) : (p.x - b.x) / (b.w || 1);
var dist = side === 'L' ? dl : side === 'R' ? dr : side === 'T' ? dt : db;
var tx = side === 'L' ? b.x : side === 'R' ? b.x + b.w : p.x, ty = side === 'T' ? b.y : side === 'B' ? b.y + b.h : p.y;
return { frac: Math.max(0, Math.min(10000, Math.round(f * 10000))), onEdge: dist <= 2, x: tx, y: ty, side: side };
}
var head = termOf(ptsR[0], P, pa), tail = termOf(ptsR[ptsR.length - 1], C, ca), p1 = head.frac, p3 = tail.frac, mid = [];
for (k = head.onEdge ? 1 : 0; k < ptsR.length - (tail.onEdge ? 1 : 0); k++) {
var q = ptsR[k], prev = mid.length ? mid[mid.length - 1] : head;
if (q.x === prev.x && q.y === prev.y) continue;
mid.push(q);
}
// ★No.237 (自己関連): astah は箱の辺のすぐ外 (1〜2 px) に折れ点を置いていても目に見える輪 (約 30 px) で描く (上司) → 辺から 10 px 以内の折れ点は 30 px 外へ
if (r.parent === r.child && mid.length && head.side === tail.side) {
var sdS = head.side, OUT = 30; // 輪の張り出し (px)。 ★ページの外 (負の座標) に出ないよう、 上・左は箱の位置までで抑える (担当者の上司 = 箱が y=21)
if (sdS === 'T') OUT = Math.max(8, Math.min(OUT, P.y - 2));
if (sdS === 'L') OUT = Math.max(8, Math.min(OUT, P.x - 2));
for (k = 0; k < mid.length; k++) {
var qS = mid[k];
if (sdS === 'T' && qS.y > P.y - 10) mid[k] = { x: qS.x, y: P.y - OUT };
else if (sdS === 'B' && qS.y < P.y + P.h + 10) mid[k] = { x: qS.x, y: P.y + P.h + OUT };
else if (sdS === 'L' && qS.x > P.x - 10) mid[k] = { x: P.x - OUT, y: qS.y };
else if (sdS === 'R' && qS.x < P.x + P.w + 10) mid[k] = { x: P.x + P.w + OUT, y: qS.y };
}
}
var allX = true, allY = true;
for (k = 0; k < mid.length; k++) {
if (mid[k].x !== head.x || mid[k].x !== tail.x) allX = false;
if (mid[k].y !== head.y || mid[k].y !== tail.y) allY = false;
}
// ★No.237: 折れ点の無い線は、 端子が中央 (5000) 以外なら「直線 (自動) = 7」で端子の位置を保つ (自動 (0) は A5M2 が経路を決め直す)。 中央なら従来どおり自動
if (!mid.length || allX || allY) return ((p1 !== 5000 || p3 !== 5000) ? '7,' : '0,') + p1 + ',5000,' + p3 + ',R,R,""';
var vs = [];
for (k = 0; k < mid.length; k++) vs.push(Math.round(mid[k].x * PX) + ';' + Math.round(mid[k].y * PX));
rmode0 = 10;
return '10,' + p1 + ',5000,' + p3 + ',R,R,"' + vs.join(';') + '"';
};
for (pi = 0; pi < rpages.length; pi++) L.push('Position="' + _a5erStr(rpages[pi]) + '",' + relPosLine(rpages[pi]));
L.push('Dependence=' + (r.dep ? '1' : '0'));
L.push('Caption=' + _a5erLine(r.caption || ''));
L.push('PName=' + _a5erLine(r.pname || ''));
L.push('LineMode=' + rmode0);
L.push('Bar1=500');
L.push('Bar2=500');
L.push('Bar3=500');
L.push('TermPos1=R');
L.push('TermPos2=R');
L.push('ZOrder=' + (model.entities.length + subs.length + ri + 1));
L.push('');
}
// 図上の注記・矩形・直線 (astah の TextPresentation / RectPresentation / LinePresentation)。 色は #RRGGBB → A5M2 の $BBGGRR
function hexColor(c) {
if (/^\$[0-9a-fA-F]{6}$/.test(String(c || ''))) return String(c).toUpperCase(); // 既に A5M2 形式 ($BBGGRR)
var m = /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(String(c || ''));
return m ? ('$' + m[3] + m[2] + m[1]).toUpperCase() : '';
}
function annHead(kind, a) {
L.push('[' + kind + ']');
if (kind === 'Comment') {
L.push('Comment=' + _a5erStr(a.text || ''));
if (a.fontSize > 0) L.push('FontSize=' + Math.round(a.fontSize)); // pt。 描画は pt × 3.528 (0.1mm) で元の比率に
}
L.push('Page=' + _a5erLine(a.page)); L.push('Left=' + Math.round(a.x * PX)); L.push('Top=' + Math.round(a.y * PX));
L.push('Width=' + Math.round(a.w * PX)); L.push('Height=' + Math.round(a.h * PX));
}
var annShapes = model.shapes || [], annLines = model.lines || [], annComments = model.comments || [], ai;
for (ai = 0; ai < annShapes.length; ai++) {
var shp = annShapes[ai];
annHead('Shape', shp);
L.push('ShapeType=' + (shp.shapeType || 'Rectangle'));
if (shp.text) L.push('Text=' + _a5erStr(shp.text)); // ★No.226: 図形の中の文字 (OBER の SHAPE VALUE)。 ★No.236: 改行は \n で保つ (Comment と同じ)
if (shp.lineType != null && shp.lineType !== 0) L.push('LineType=' + shp.lineType); // 1 = 線無し (テキスト) / 2 = 破線
if (hexColor(shp.lineColor)) L.push('LineColor=' + hexColor(shp.lineColor));
if (hexColor(shp.brushColor)) L.push('BrushColor=' + hexColor(shp.brushColor));
if (shp.brushAlpha != null && !isNaN(shp.brushAlpha)) L.push('BrushAlpha=' + Math.max(0, Math.min(255, Math.round(shp.brushAlpha)))); // ★No.236: 0 = 透明 (枠無しテキスト)
if (parseInt(shp.lineWidth, 10) > 0) L.push('LineWidth=' + parseInt(shp.lineWidth, 10));
if (shp.fontSize > 0) L.push('FontSize=' + Math.round(shp.fontSize));
if (shp.fontBold) L.push('FontBold=1');
if (hexColor(shp.fontColor)) L.push('FontColor=' + hexColor(shp.fontColor));
if (shp.z != null && !isNaN(shp.z)) L.push('ZOrder=' + shp.z); // ★Ver1.0.22 (No.199): 元ツールの重なり順 (大きいほど手前)
L.push('');
}
for (ai = 0; ai < annLines.length; ai++) {
var lin = annLines[ai];
annHead('Line', lin);
if (hexColor(lin.lineColor)) L.push('LineColor=' + hexColor(lin.lineColor));
if (parseInt(lin.lineWidth, 10) > 0) L.push('LineWidth=' + parseInt(lin.lineWidth, 10));
if (lin.lineType != null && lin.lineType !== 0) L.push('LineType=' + lin.lineType);
if (lin.startTerm) L.push('StartLineTermType=' + lin.startTerm); // ★No.226: 端の形 (4 = ▶)
if (lin.endTerm) L.push('EndLineTermType=' + lin.endTerm);
if (lin.z != null && !isNaN(lin.z)) L.push('ZOrder=' + lin.z);
L.push('');
}
for (ai = 0; ai < annComments.length; ai++) {
var cmt = annComments[ai];
annHead('Comment', cmt);
if (hexColor(cmt.bkColor)) L.push('BkColor=' + hexColor(cmt.bkColor));
if (hexColor(cmt.lineColor)) L.push('LineColor=' + hexColor(cmt.lineColor));
if (hexColor(cmt.fontColor)) L.push('FontColor=' + hexColor(cmt.fontColor)); // ★No.236: 付箋の文字色 (仕様書 4.7)
if (cmt.z != null && !isNaN(cmt.z)) L.push('ZOrder=' + cmt.z);
L.push('');
}
return '' + L.join('\r\n');
}
// 入力の種類を見て .a5er を作る (ページ / テストの共通入口)。 opts.noComment = DDL のコメントを論理名にしない
function _edmConvToA5er(text, opts) {
if (text && typeof text === 'object' && text.asta) { // astah (.asta): ページ側で ZIP から取り出した EntityStore (Java 直列化) の { asta: 1, name, bytes }
var am = _astaParse(text);
return { kind: 'asta', a5er: am.entities.length ? _a5erWriteModel(am) : '', stats: am.stats, warnings: am.warnings, name: am.name };
}
var t = String(text || '').replace(/^/, '');
if (/^\s*\x7B\s*"vsdx"/.test(t.substring(0, 20))) { // \x7B = 波括弧 (関数抽出の波括弧数えを壊さないため)
// Visio (.vsdx): ページ側で ZIP を展開して {vsdx:1, name, pages:[{name, w, h, xml}]} の JSON にしたもの
var vm = _vsdxParse(JSON.parse(t));
return { kind: 'vsdx', a5er: vm.entities.length ? _a5erWriteModel(vm) : '', stats: vm.stats, warnings: vm.warnings, name: vm.name };
}
if (/<ERD\b/.test(t.substring(0, 4000))) {
var model = _oberParse(t);
if (!model) throw new Error('not an OBER file');
return { kind: 'ober', a5er: _a5erWriteModel(model), stats: model.stats, warnings: model.warnings, name: model.name };
}
// ★Ver1.0.22: DDL (.sql) の変換は廃止 (ユーザー決定 2026-09-29)。 ここまで来た平文は対応外の形式
throw new Error('unsupported format (expected SI Object Browser ER .edm / Visio .vsdx / astah .asta)');
}
TFE.edmConvToA5er = _edmConvToA5er;
// [[EDMCONV-MODULE-END]]
// ---- 短い別名 ----
TFE.a5erNorm = _a5erNorm; // 本体の EDM 属性カタログが名前の正規化に使う
TFE.renderSvg = _renderA5erToSvg;
TFE.contentPages = _a5erContentPages;
TFE.previewSvg = _tfcEdmPreviewSvg;
TFE.groupFks = _groupFks;
TFE.erToA5er = _erToA5er;
TFE.writeModel = _a5erWriteModel;
TFE.convert = _edmConvToA5er;
TFE.vsdxUnzip = _vsdxUnzip;
TFE.vsdxBundle = _vsdxBundle;
TFE.vsdxParse = _vsdxParse;
TFE.astaDeser = _astaDeser;
TFE.astaParse = _astaParse;
TFE.oberParse = _oberParse;
TFE.s = _erS;
TFE.escapeHtml = _erEsc;
TFE.escapeAttr = _erEscAttr;
TFE.t = _erT;
TFE.LABELS = _erLabels;
// export
global.TFE = TFE;
return TFE;
})(this);
≣ サーバJS ライブラリTLN_FUNC_TEST_JAVA TLN_FUNC_TEST_JAVA 2字
//
≣ サーバJS ライブラリWCRG_COMMON WCRG_共通クラス群 21653字
function createPoolRanking(_CND_DTYEAR, _CND_KBPOOL) {
var sql = "" +
"SELECT " +
" POINT_LIST.DTYEAR " +
", POINT_LIST.KBPOOL " +
", POINT_LIST.IDTEAM " +
", POINT_LIST.TXNAME " +
", SUM(POINT_LIST.POINT_SCORE) AS VLPOINT " +
", SUM(POINT_LIST.SCORE_M - POINT_LIST.SCORE_A) AS VLTOKUSITTEN " +
", SUM(POINT_LIST.VLTRYCNT_M - POINT_LIST.VLTRYCNT_A) AS VLTRYSASU " +
", SUM(POINT_LIST.SCORE_M) AS VLTOKUTEN " +
", SUM(POINT_LIST.VLTRYCNT_M) AS VLTRYSU " +
", WCRG_AT040.VLRANKW " +
", 0 AS VLWINPOINT " +
"FROM ( " +
" SELECT " +
" WCRG_V_LEAGUE_LIST.DTYEAR " +
" , WCRG_V_LEAGUE_LIST.KBPOOL " +
" , WCRG_V_LEAGUE_LIST.IDTEAM1 AS IDTEAM " +
" , WCRG_V_LEAGUE_LIST.TXNAME1 AS TXNAME " +
" , case when WCRG_V_LEAGUE_LIST.POINT_SCORE1 is null then 0 else WCRG_V_LEAGUE_LIST.POINT_SCORE1 end AS POINT_SCORE " +
" , WCRG_V_LEAGUE_LIST.SCORE1 AS SCORE_M " +
" , WCRG_V_LEAGUE_LIST.SCORE2 AS SCORE_A " +
" , WCRG_V_LEAGUE_LIST.VLTRYCNT1 AS VLTRYCNT_M " +
" , WCRG_V_LEAGUE_LIST.VLTRYCNT2 AS VLTRYCNT_A " +
" FROM WCRG_V_LEAGUE_LIST " +
" WHERE WCRG_V_LEAGUE_LIST.DTYEAR = '" + _CND_DTYEAR + "' " +
" AND WCRG_V_LEAGUE_LIST.KBPOOL = '" + _CND_KBPOOL + "' " +
" " +
" UNION ALL " +
" " +
" SELECT " +
" DTYEAR " +
" , KBPOOL " +
" , IDTEAM2 AS IDTEAM " +
" , TXNAME2 AS TXNAME " +
" , case when POINT_SCORE2 is null then 0 else POINT_SCORE2 end AS POINT_SCORE " +
" , WCRG_V_LEAGUE_LIST.SCORE2 AS SCORE_M " +
" , WCRG_V_LEAGUE_LIST.SCORE1 AS SCORE_A " +
" , WCRG_V_LEAGUE_LIST.VLTRYCNT2 AS VLTRYCNT_M " +
" , WCRG_V_LEAGUE_LIST.VLTRYCNT1 AS VLTRYCNT_A " +
" FROM WCRG_V_LEAGUE_LIST " +
" WHERE WCRG_V_LEAGUE_LIST.DTYEAR = '" + _CND_DTYEAR + "' " +
" AND WCRG_V_LEAGUE_LIST.KBPOOL = '" + _CND_KBPOOL + "' " +
") POINT_LIST " +
" " +
"LEFT OUTER JOIN WCRG_AT040 " +
" ON POINT_LIST.DTYEAR = WCRG_AT040.DTYEAR " +
" AND POINT_LIST.IDTEAM = WCRG_AT040.IDTEAM " +
" " +
"GROUP BY " +
" POINT_LIST.DTYEAR " +
", POINT_LIST.KBPOOL " +
", POINT_LIST.IDTEAM " +
", POINT_LIST.TXNAME " +
", WCRG_AT040.VLRANKW " +
" " +
"ORDER BY " +
" POINT_LIST.DTYEAR " +
", POINT_LIST.KBPOOL " +
", SUM(POINT_LIST.POINT_SCORE) DESC " +
", SUM(POINT_LIST.SCORE_M - POINT_LIST.SCORE_A) DESC " +
", SUM(POINT_LIST.VLTRYCNT_M - POINT_LIST.VLTRYCNT_A) DESC " +
", SUM(POINT_LIST.SCORE_M) DESC " +
", SUM(POINT_LIST.VLTRYCNT_M) DESC " +
", WCRG_AT040.VLRANKW " +
" ";
var itemSelectListMain = TalonDbUtil.select( TALON.getDbConfig() , sql );
var itemSelectListSub = itemSelectListMain;
for (var iMain = 0; iMain < itemSelectListMain.length; iMain++) {
var lineDataMapMain = itemSelectListMain[iMain];
var _DTYEAR = lineDataMapMain['DTYEAR'];
var _KBPOOL = lineDataMapMain['KBPOOL'];
var _M_IDTEAM = lineDataMapMain['IDTEAM'];
var _M_TXNAME = lineDataMapMain['TXNAME'];
var _M_VLPOINT = lineDataMapMain['VLPOINT'];
var _M_VLTOKUSITTEN = lineDataMapMain['VLTOKUSITTEN'];
var _M_VLTRYSASU = lineDataMapMain['VLTRYSASU'];
var _M_VLTOKUTEN = lineDataMapMain['VLTOKUTEN'];
var _M_VLTRYSU = lineDataMapMain['VLTRYSU'];
var _M_VLRANKW = lineDataMapMain['VLPOINT'];
var _M_VLWINPOINT = 0;
for (var iSub = 0; iSub < itemSelectListSub.length; iSub++) {
var lineDataMapSub = itemSelectListSub[iMain];
var _S_IDTEAM = lineDataMapSub['IDTEAM'];
var _S_VLPOINT = lineDataMapSub['VLPOINT'];
if (_M_VLPOINT == _S_VLPOINT) {
_M_VLWINPOINT = _M_VLWINPOINT + getWinPoint(_DTYEAR, _KBPOOL, _M_IDTEAM, _S_IDTEAM);
}
}
lineDataMapMain['VLWINPOINT'] = _M_VLWINPOINT;
var sql = "" +
"INSERT INTO WCRG_WK020 ( " +
" DTYEAR " +
" , KBPOOL " +
" , IDTEAM " +
" , TXNAME " +
" , VLPOINT " +
" , VLWINPOINT " +
" , VLTOKUSITTEN " +
" , VLTRYSASU " +
" , VLTOKUTEN " +
" , VLTRYSU " +
" , VLRANKW " +
") VALUES ( " +
" '" + _DTYEAR + "'" +
" , '" + _KBPOOL + "'" +
" , '" + _M_IDTEAM + "'" +
" , '" + _M_TXNAME + "'" +
" , " + _M_VLPOINT + " " +
" , " + _M_VLWINPOINT + " " +
" , " + _M_VLTOKUSITTEN + " " +
" , " + _M_VLTRYSASU + " " +
" , " + _M_VLTOKUTEN + " " +
" , " + _M_VLTRYSU + " " +
" , " + _M_VLRANKW + " " +
") " +
" ";
var insertCount = TalonDbUtil.insert( TALON.getDbConfig() , sql );
}
var sql = "" +
"SELECT " +
" DTYEAR " +
", KBPOOL " +
", IDTEAM " +
", TXNAME " +
", VLPOINT " +
", VLWINPOINT " +
", VLTOKUSITTEN " +
", VLTRYSASU " +
", VLTOKUTEN " +
", VLTRYSU " +
", VLRANKW " +
", VLRANKNUMBER " +
"FROM WCRG_WK020 " +
"ORDER BY " +
" VLPOINT " +
", VLWINPOINT " +
", VLTOKUSITTEN " +
", VLTRYSASU " +
", VLTOKUTEN " +
", VLTRYSU " +
", VLRANKW " +
" ";
for (var iMain = 0; iMain < itemSelectListMain.length; iMain++) {
var lineDataMapMain = itemSelectListMain[iMain];
var _DTYEAR = lineDataMapMain['DTYEAR'];
var _KBPOOL = lineDataMapMain['KBPOOL'];
var _M_IDTEAM = lineDataMapMain['IDTEAM'];
var sql = "" +
"UPDATE WCRG_WK020 SET " +
" VLRANKNUMBER = " + (iMain + 1) + " " +
"WHERE DTYEAR = '" + _DTYEAR + "'" +
" AND KBPOOL = '" + _KBPOOL + "'" +
" AND IDTEAM = '" + _M_IDTEAM + "'" +
" ";
var updateCount = TalonDbUtil.update( TALON.getDbConfig() , sql );
}
}
function getWinPoint(_DTYEAR, _KBPOOL, _M_IDTEAM, _S_IDTEAM) {
var sql = "" +
"SELECT " +
"WINPTN " +
"FROM ( " +
" SELECT " +
" case when ( (case when SCORE1 is null then 0 else SCORE1 end) > (case when SCORE2 is null then 0 else SCORE2 end) ) then 1 else 0 end AS WINPTN " +
" FROM WCRG_V_LEAGUE_LIST " +
" WHERE DTYEAR = '2019' " +
" AND KBPOOL = 'PL-A' " +
" AND IDTEAM1 = 'TM10' " +
" AND IDTEAM2 = 'TM13' " +
" " +
" UNION ALL " +
" " +
" SELECT " +
" case when ( (case when SCORE2 is null then 0 else SCORE2 end) > (case when SCORE1 is null then 0 else SCORE1 end) ) then 1 else 0 end AS WINPTN " +
" FROM WCRG_V_LEAGUE_LIST " +
" WHERE DTYEAR = '2019' " +
" AND KBPOOL = 'PL-A' " +
" AND IDTEAM1 = 'TM13' " +
" AND IDTEAM2 = 'TM10' " +
") MN " +
" ";
var itemSelectListPoint = TalonDbUtil.select( TALON.getDbConfig() , sql );
if (itemSelectListPoint.length == 0 ) {
var _WINPTN = 0;
} else {
var lineDataMapPoint = itemSelectListPoint[0];
var _WINPTN = lineDataMapPoint['WINPTN'];
}
return _WINPTN;
}
// -----------------------------------------------------------------------------
function createTournamentList(_CND_DTYEAR){
//準々決勝:プール戦結果
var sql = "" +
"SELECT " +
" WCRG_AT030.DTYEAR " +
", WCRG_AT030.SQTMATCH " +
", WCRG_AT030.SQTMATCHUP " +
", WCRG_AT030.VLWAKU " +
", WCRG_WK020_1.IDTEAM AS IDTEAM1 " +
", WCRG_WK020_1.TXNAME AS TXNAME1 " +
", WCRG_WK020_2.IDTEAM AS IDTEAM2 " +
", WCRG_WK020_2.TXNAME AS TXNAME2 " +
"FROM WCRG_AT030 " +
"LEFT OUTER JOIN WCRG_WK020 WCRG_WK020_1 " +
" ON WCRG_AT030.DTYEAR = WCRG_WK020_1.DTYEAR " +
" AND WCRG_AT030.KBPOOL1 = WCRG_WK020_1.KBPOOL " +
" AND WCRG_WK020_1.VLRANKNUMBER = 1 " +
"LEFT OUTER JOIN WCRG_WK020 WCRG_WK020_2 " +
" ON WCRG_AT030.DTYEAR = WCRG_WK020_2.DTYEAR " +
" AND WCRG_AT030.KBPOOL2 = WCRG_WK020_2.KBPOOL " +
" AND WCRG_WK020_2.VLRANKNUMBER = 2 " +
"WHERE WCRG_AT030.KBPOOL1 IS NOT NULL "
" AND WCRG_AT030.DTYEAR = '" + _CND_DTYEAR + "' ";
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
for (var i = 0; i < itemSelectList.length; i++) {
var lineDataMap = itemSelectList[i];
insertWCRG_WK030(lineDataMap['DTYEAR'], lineDataMap['SQTMATCH'], lineDataMap['IDTEAM1'], lineDataMap['TXNAME1'], lineDataMap['IDTEAM2'], lineDataMap['TXNAME2']) ;
}
//準決勝:準々決勝結果(勝)
var sql = selectWCRG_WK030(_CND_DTYEAR, 2, 0);
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
for (var i = 0; i < itemSelectList.length; i++) {
var lineDataMap = itemSelectList[i];
insertWCRG_WK030(lineDataMap['DTYEAR'], lineDataMap['SQTMATCH'], lineDataMap['IDTEAM1'], lineDataMap['TXNAME1'], lineDataMap['IDTEAM2'], lineDataMap['TXNAME2']) ;
}
//決勝:準決勝結果(勝)
var sql = selectWCRG_WK030(_CND_DTYEAR, 0, 0);
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
for (var i = 0; i < itemSelectList.length; i++) {
var lineDataMap = itemSelectList[i];
insertWCRG_WK030(lineDataMap['DTYEAR'], lineDataMap['SQTMATCH'], lineDataMap['IDTEAM1'], lineDataMap['TXNAME1'], lineDataMap['IDTEAM2'], lineDataMap['TXNAME2']) ;
}
//3位決定戦:準決勝結果(負)
var sql = selectWCRG_WK030(_CND_DTYEAR, 1, 1);
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
for (var i = 0; i < itemSelectList.length; i++) {
var lineDataMap = itemSelectList[i];
insertWCRG_WK030(lineDataMap['DTYEAR'], lineDataMap['SQTMATCH'], lineDataMap['IDTEAM1'], lineDataMap['TXNAME1'], lineDataMap['IDTEAM2'], lineDataMap['TXNAME2']) ;
}
}
/*
_VLLEVEL 参照する階層
_KBN 0:勝者チーム 1:敗者チーム
*/
function selectWCRG_WK030(_DTYEAR, _VLLEVEL, _KBN) {
var sql = "";
//3位決定戦の場合、決勝の負けを取得
if (_VLLEVEL == 1) {
sql = sql + "" +
"SELECT DTYEAR, SQTMATCH FROM WCRG_AT030 " +
"WHERE WCRG_AT030.DTYEAR = '" + _DTYEAR + "' " +
" AND WCRG_AT030.VLLEVEL= " + _VLLEVEL + " "
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
var lineDataMap = itemSelectList[0];
var _SQTMATCH = lineDataMap['SQTMATCH'];
}
var sql = "";
if (_VLLEVEL == 1) {
sql = sql + "" +
"SELECT " +
" " +
" WCRG_AT030.DTYEAR " +
", '" + _SQTMATCH + "' as SQTMATCH " +
" ";
_VLLEVEL = 0;
} else {
sql = sql + "" +
"SELECT " +
" " +
" WCRG_AT030.DTYEAR " +
", WCRG_AT030.SQTMATCH " +
" ";
}
if (_KBN == 1) {
//3位決定戦 : 敗者を取得
sql = sql + "" +
", CASE " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1>WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.IDTEAM2 " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1<WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.IDTEAM1 " +
" ELSE NULL " +
" END AS IDTEAM1 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1>WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.TXNAME2 " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1<WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.TXNAME1 " +
" ELSE NULL " +
" END AS TXNAME1 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1>WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.IDTEAM2 " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1<WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.IDTEAM1 " +
" ELSE NULL " +
" END AS IDTEAM2 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1>WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.TXNAME2 " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1<WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.TXNAME1 " +
" ELSE NULL " +
" END AS TXNAME2 " +
" ";
} else {
//準決勝・決勝時 : 勝者を取得
sql = sql + "" +
", CASE " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1>WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.IDTEAM1 " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1<WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.IDTEAM2 " +
" ELSE NULL " +
" END AS IDTEAM1 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1>WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.TXNAME1 " +
" WHEN WCRG_AT030_KEKKA1.ALLSCORE1<WCRG_AT030_KEKKA1.ALLSCORE2 THEN WCRG_AT030_KEKKA1.TXNAME2 " +
" ELSE NULL " +
" END AS TXNAME1 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1>WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.IDTEAM1 " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1<WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.IDTEAM2 " +
" ELSE NULL " +
" END AS IDTEAM2 " +
" " +
", CASE " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1>WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.TXNAME1 " +
" WHEN WCRG_AT030_KEKKA2.ALLSCORE1<WCRG_AT030_KEKKA2.ALLSCORE2 THEN WCRG_AT030_KEKKA2.TXNAME2 " +
" ELSE NULL " +
" END AS TXNAME2 " +
" ";
}
sql = sql + "" +
"FROM WCRG_AT030 " +
" " +
"LEFT OUTER JOIN ( " +
" SELECT " +
" " +
" WCRG_AT030.DTYEAR " +
" , WCRG_AT030.SQTMATCH " +
" , WCRG_AT030.VLLEVEL " +
" , WCRG_AT030.VLWAKU " +
" , WCRG_AT030.SQTMATCHUP " +
" " +
" , WCRG_WK030.IDTEAM1 " +
" , WCRG_WK030.TXNAME1 " +
" , case when WCRG_AT032_1.ALLSCORE is null then 0 else WCRG_AT032_1.ALLSCORE end AS ALLSCORE1 " +
" " +
" , WCRG_WK030.IDTEAM2 " +
" , WCRG_WK030.TXNAME2 " +
" , case when WCRG_AT032_2.ALLSCORE is null then 0 else WCRG_AT032_2.ALLSCORE end AS ALLSCORE2 " +
" " +
" FROM WCRG_AT030 " +
" " +
" LEFT OUTER JOIN WCRG_WK030 " +
" ON WCRG_AT030.DTYEAR = WCRG_WK030.DTYEAR " +
" AND WCRG_AT030.SQTMATCH = WCRG_WK030.SQTMATCH " +
" " +
" LEFT OUTER JOIN ( " +
" SELECT " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ,SUM( " +
" ( case when VLTRYCNT is null then 0 else VLTRYCNT end * 5 ) " +
" + " +
" ( case when VLCNVCNT is null then 0 else VLCNVCNT end * 2 ) " +
" + " +
" ( case when VLPENCNT is null then 0 else VLPENCNT end * 3 ) " +
" + " +
" ( case when VLDRPCNT is null then 0 else VLDRPCNT end * 3 ) " +
" ) AS ALLSCORE " +
" FROM WCRG_AT032 " +
" GROUP BY " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ) WCRG_AT032_1 " +
" ON WCRG_WK030.DTYEAR = WCRG_AT032_1.DTYEAR " +
" AND WCRG_WK030.SQTMATCH = WCRG_AT032_1.SQTMATCH " +
" AND WCRG_WK030.IDTEAM1 = WCRG_AT032_1.IDTEAM " +
" " +
" LEFT OUTER JOIN ( " +
" SELECT " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ,SUM( " +
" ( case when VLTRYCNT is null then 0 else VLTRYCNT end * 5 ) " +
" + " +
" ( case when VLCNVCNT is null then 0 else VLCNVCNT end * 2 ) " +
" + " +
" ( case when VLPENCNT is null then 0 else VLPENCNT end * 3 ) " +
" + " +
" ( case when VLDRPCNT is null then 0 else VLDRPCNT end * 3 ) " +
" ) AS ALLSCORE " +
" FROM WCRG_AT032 " +
" GROUP BY " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ) WCRG_AT032_2 " +
" ON WCRG_WK030.DTYEAR = WCRG_AT032_2.DTYEAR " +
" AND WCRG_WK030.SQTMATCH = WCRG_AT032_2.SQTMATCH " +
" AND WCRG_WK030.IDTEAM2 = WCRG_AT032_2.IDTEAM " +
" WHERE WCRG_AT030.VLWAKU = 1 " +
") WCRG_AT030_KEKKA1 " +
" ON WCRG_AT030.DTYEAR = WCRG_AT030_KEKKA1.DTYEAR " +
" AND WCRG_AT030.SQTMATCH = WCRG_AT030_KEKKA1.SQTMATCHUP " +
" " +
"LEFT OUTER JOIN ( " +
" SELECT " +
" " +
" WCRG_AT030.DTYEAR " +
" , WCRG_AT030.SQTMATCH " +
" , WCRG_AT030.VLLEVEL " +
" , WCRG_AT030.VLWAKU " +
" , WCRG_AT030.SQTMATCHUP " +
" " +
" , WCRG_WK030.IDTEAM1 " +
" , WCRG_WK030.TXNAME1 " +
" , WCRG_AT032_1.ALLSCORE AS ALLSCORE1 " +
" " +
" , WCRG_WK030.IDTEAM2 " +
" , WCRG_WK030.TXNAME2 " +
" , WCRG_AT032_2.ALLSCORE AS ALLSCORE2 " +
" " +
" FROM WCRG_AT030 " +
" " +
" LEFT OUTER JOIN WCRG_WK030 " +
" ON WCRG_AT030.DTYEAR = WCRG_WK030.DTYEAR " +
" AND WCRG_AT030.SQTMATCH = WCRG_WK030.SQTMATCH " +
" " +
" LEFT OUTER JOIN ( " +
" SELECT " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ,SUM( " +
" ( case when VLTRYCNT is null then 0 else VLTRYCNT end * 5 ) " +
" + " +
" ( case when VLCNVCNT is null then 0 else VLCNVCNT end * 2 ) " +
" + " +
" ( case when VLPENCNT is null then 0 else VLPENCNT end * 3 ) " +
" + " +
" ( case when VLDRPCNT is null then 0 else VLDRPCNT end * 3 ) " +
" ) AS ALLSCORE " +
" FROM WCRG_AT032 " +
" GROUP BY " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ) WCRG_AT032_1 " +
" ON WCRG_WK030.DTYEAR = WCRG_AT032_1.DTYEAR " +
" AND WCRG_WK030.SQTMATCH = WCRG_AT032_1.SQTMATCH " +
" AND WCRG_WK030.IDTEAM1 = WCRG_AT032_1.IDTEAM " +
" " +
" LEFT OUTER JOIN ( " +
" SELECT " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ,SUM( " +
" ( case when VLTRYCNT is null then 0 else VLTRYCNT end * 5 ) " +
" + " +
" ( case when VLCNVCNT is null then 0 else VLCNVCNT end * 2 ) " +
" + " +
" ( case when VLPENCNT is null then 0 else VLPENCNT end * 3 ) " +
" + " +
" ( case when VLDRPCNT is null then 0 else VLDRPCNT end * 3 ) " +
" ) AS ALLSCORE " +
" FROM WCRG_AT032 " +
" GROUP BY " +
" DTYEAR " +
" ,SQTMATCH " +
" ,IDTEAM " +
" ) WCRG_AT032_2 " +
" ON WCRG_WK030.DTYEAR = WCRG_AT032_2.DTYEAR " +
" AND WCRG_WK030.SQTMATCH = WCRG_AT032_2.SQTMATCH " +
" AND WCRG_WK030.IDTEAM2 = WCRG_AT032_2.IDTEAM " +
" WHERE WCRG_AT030.VLWAKU = 2 " +
") WCRG_AT030_KEKKA2 " +
" ON WCRG_AT030.DTYEAR = WCRG_AT030_KEKKA2.DTYEAR " +
" AND WCRG_AT030.SQTMATCH = WCRG_AT030_KEKKA2.SQTMATCHUP " +
" " +
"WHERE WCRG_AT030.DTYEAR = '" + _DTYEAR + "' " +
" AND WCRG_AT030.VLLEVEL= " + _VLLEVEL + " " +
" ";
return sql;
}
function insertWCRG_WK030(_DTYEAR, _SQTMATCH, _IDTEAM1, _TXNAME1, _IDTEAM2, _TXNAME2 ) {
if (_IDTEAM1 == null) { _IDTEAM1 = ""; }
if (_TXNAME1 == null) { _TXNAME1 = ""; }
if (_IDTEAM2 == null) { _IDTEAM2 = ""; }
if (_TXNAME2 == null) { _TXNAME2 = ""; }
var sql = "" +
"INSERT INTO WCRG_WK030 ( " +
" DTYEAR " +
", SQTMATCH " +
", IDTEAM1 " +
", TXNAME1 " +
", IDTEAM2 " +
", TXNAME2 " +
") VALUES ( " +
" '" + _DTYEAR + "' " +
", '" + _SQTMATCH + "' " +
", '" + _IDTEAM1 + "' " +
", '" + _TXNAME1 + "' " +
", '" + _IDTEAM2 + "' " +
", '" + _TXNAME2 + "' " +
") ";
var insertCount = TalonDbUtil.insert( TALON.getDbConfig() , sql );
}
≣ サーバJS ライブラリWFS_COMMON [共通]ワークフローシステム 59371字
/**
* WFS_COMMON : [共通]ワークフローシステム
*
* 最終更新: WFS_2_0_3
* @version 2025/07/29
*/
//-------------------------------------------
//[共通]部品
//-------------------------------------------
var _USER_ID = '';
var _FUNC_ID = '';
function tln_com_escape(val) {
var toStr = Object.prototype.toString;
var tType = toStr.call( val ).slice(8, -1).toUpperCase();
if (tType == 'STRING' ) {
return val.replace( /'/g , "''" );
} else {
return val;
}
}
function tln_com_nowdate() {
var sysDate = new java.util.Date();
return sysDate;
}
function tln_com_todate(val) {
y = parseInt(val.split("/")[0]) - 1900;
m = parseInt(val.split("/")[1]) - 1;
d = parseInt(val.split("/")[2]);
var sysDate = new java.util.Date(y,m,d);
return sysDate;
}
function tln_com_func_id() {
if (_FUNC_ID == '') {
_FUNC_ID = TALON.getUserInfoMap().get("FUNC_ID");
}
return _FUNC_ID;
}
function tln_com_user_id() {
if (_USER_ID == '') {
var lineDataMap = TALON.getUserInfoMap();
_USER_ID = getMapVal( lineDataMap , 'USER_ID' );
}
return _USER_ID;
}
function tln_com_log(val) {
var log = TALON.getLogger();
log.writeDebug(val);
}
//-------------------------------------------
//[共通]部品0
//-------------------------------------------
function tln_insertByMap(tbl, lst ,name) {
if ( chkLowercase() ) {
TalonDbUtil.insertByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name );
} else {
TalonDbUtil.insertByMap( TALON.getDbConfig(), tbl , lst , name );
}
}
function tln_updateByMap(tbl, lst ,name ,where) {
if ( chkLowercase() ) {
TalonDbUtil.updateByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name , where);
} else {
TalonDbUtil.updateByMap( TALON.getDbConfig(), tbl , lst , name , where);
}
}
function tln_deleteByMap(tbl, lst ,name) {
if ( chkLowercase() ) {
TalonDbUtil.deleteByMap( TALON.getDbConfig(), tbl.toLowerCase(), lst , name );
} else {
TalonDbUtil.deleteByMap( TALON.getDbConfig(), tbl , lst , name );
}
}
//-------------------------------------------
//[共通]処理0
//-------------------------------------------
function getMapVal(map , id) {
var _rec = null;
_rec = map[id];
if (_rec == null) {
_rec = map[id.toLowerCase()];
}
return _rec;
}
function setMapVal(map , id , val) {
if ( TALON.getDbConfig().isPostgres() ) {
map[ id.toLowerCase() ] = val;
} else {
map[ id ] = val;
}
}
function putBindVal(key , val) {
if ( TALON.getDbConfig().isPostgres() ) {
TALON.putBindValue( key.toLowerCase() , val );
} else {
TALON.putBindValue( key , val );
}
}
function chkLowercase() {
if ( TALON.getDbConfig().isPostgres() ) {
return true;
} else if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE BINARY TABLE_NAME = BINARY 'WFS_M_AUTH' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal( lineDataMap , 'CNT' );
if (_CNT == 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
function editLowList(obj) {
if ( TALON.getDbConfig().isPostgres() ) {
for(var lop = 0; lop < obj.length; lop++) {
obj[lop] = obj[lop].toLowerCase();
}
}
return obj;
}
//-------------------------------------------
//[共通]処理
//-------------------------------------------
//-------------------------------------------
//WFSワークフロー管理マスタ
function selectWFS_M_CONTROL(_WORK_ID) {
var sql =
"SELECT " +
" WORK_ID " +
", WORK_NM " +
", LVL_ROWS " +
", REJECT_KBN " +
", DAIRI_FLG " +
", MAIL_SEND_FLG " +
", CREATED_DATE " +
", CREATED_BY " +
", CREATED_PRG_NM " +
", UPDATED_DATE " +
", UPDATED_BY " +
", UPDATED_PRG_NM " +
", MODIFY_COUNT " +
"FROM WFS_M_CONTROL " +
"WHERE WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
//WFSワークフロー階層マスタ
function selectWFS_M_LEVEL(_WORK_ID, _LVL, _ROUTE_ID) {
var sql =
"SELECT " +
" WFS_M_LEVEL.WORK_ID " +
", WFS_M_LEVEL.LVL " +
", WFS_M_LEVEL.LVL_NM " +
", CASE WHEN WFS_M_LEVEL.SYONIN_PTN IS NOT NULL THEN WFS_M_LEVEL.SYONIN_PTN ELSE WFS_M_AUTH.SYONIN_PTN END AS SYONIN_PTN " +
", WFS_M_LEVEL.CREATED_DATE " +
", WFS_M_LEVEL.CREATED_BY " +
", WFS_M_LEVEL.CREATED_PRG_NM " +
", WFS_M_LEVEL.UPDATED_DATE " +
", WFS_M_LEVEL.UPDATED_BY " +
", WFS_M_LEVEL.UPDATED_PRG_NM " +
", WFS_M_LEVEL.MODIFY_COUNT " +
"FROM WFS_M_LEVEL " +
"LEFT OUTER JOIN WFS_M_AUTH " +
" ON WFS_M_LEVEL.WORK_ID = WFS_M_AUTH.WORK_ID " +
" AND WFS_M_LEVEL.LVL = WFS_M_AUTH.LVL " +
" AND '" + tln_com_escape( _ROUTE_ID ) + "' = WFS_M_AUTH.ROUTE_ID " +
"WHERE WFS_M_LEVEL.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND WFS_M_LEVEL.LVL = '" + tln_com_escape( _LVL ) + "'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
function selectWFS_M_LEVEL_NEXTPRE(_WORK_ID,_ROUTE_ID,_LVL,_FLG) {
//_FLG : 1 = 次のレベル / ELSE = 前のレベル
var wh = '';
if (_FLG == '1') {
wh = " AND WFS_M_LEVEL.LVL > '" + _LVL + "' " +
"ORDER BY WFS_M_LEVEL.LVL ";
} else {
wh = " AND WFS_M_LEVEL.LVL < '" + _LVL + "' " +
"ORDER BY WFS_M_LEVEL.LVL DESC ";
}
var sql =
"SELECT " +
" WFS_M_LEVEL.LVL " +
"FROM WFS_M_LEVEL " +
"INNER JOIN WFS_M_AUTH " +
" ON WFS_M_AUTH.WORK_ID = WFS_M_LEVEL.WORK_ID " +
" AND WFS_M_AUTH.LVL = WFS_M_LEVEL.LVL " +
" AND WFS_M_AUTH.ROUTE_ID = '" + tln_com_escape( _ROUTE_ID ) + "'" +
"WHERE WFS_M_LEVEL.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
wh
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
//WFSワークフローグループ権限割り付けマスタ
function selectWFS_M_AUTH(_WORK_ID,_LVL,_ROUTE_ID) {
var sql =
"SELECT " +
" WORK_ID " +
", LVL " +
", ROUTE_ID " +
", USR_GRP_ID " +
", CREATED_DATE " +
", CREATED_BY " +
", CREATED_PRG_NM " +
", UPDATED_DATE " +
", UPDATED_BY " +
", UPDATED_PRG_NM " +
", MODIFY_COUNT " +
"FROM WFS_M_AUTH " +
"WHERE WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND LVL = '" + tln_com_escape( _LVL ) + "'" +
" AND ROUTE_ID = '" + tln_com_escape( _ROUTE_ID ) + "'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
//WFSワークフローグループ権限割り付けマスタ
function selectWFS_M_AUTH_TANTO_CNT(_WORK_ID,_LVL,_ROUTE_ID,_OBJECT_ID) {
//承認者指定を行っている場合はその人数が次階層に移動する基準となる
var sql =
"SELECT " +
" WFS_M_AUTH.WORK_ID " +
",WFS_M_AUTH.LVL " +
",WFS_M_AUTH.ROUTE_ID " +
",WFS_M_AUTH.USR_GRP_ID " +
",CASE WHEN WFS_T_WORKAPPROVALRES_CNT.CNT IS NULL THEN COUNT(*) ELSE WFS_T_WORKAPPROVALRES_CNT.CNT END as TANTO_CNT " +
"FROM WFS_M_AUTH " +
"INNER JOIN WFS_M_USR_GRP_DEPDTL " +
" ON WFS_M_USR_GRP_DEPDTL.USR_GRP_ID = WFS_M_AUTH.USR_GRP_ID " +
"LEFT OUTER JOIN ( " +
" SELECT " +
" WORK_ID " +
" ,OBJECT_ID " +
" ,LVL " +
" ,COUNT(*) AS CNT " +
" FROM WFS_T_WORKAPPROVALRES " +
" GROUP BY " +
" WORK_ID " +
" ,OBJECT_ID " +
" ,LVL " +
" ) WFS_T_WORKAPPROVALRES_CNT " +
" ON WFS_M_AUTH.WORK_ID = WFS_T_WORKAPPROVALRES_CNT.WORK_ID " +
" AND '" + _OBJECT_ID + "' = WFS_T_WORKAPPROVALRES_CNT.OBJECT_ID " +
" AND WFS_M_AUTH.LVL = WFS_T_WORKAPPROVALRES_CNT.LVL " +
"WHERE WFS_M_AUTH.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND WFS_M_AUTH.LVL = '" + tln_com_escape( _LVL ) + "'" +
" AND WFS_M_AUTH.ROUTE_ID = '" + tln_com_escape( _ROUTE_ID ) + "'" +
"GROUP BY " +
" WFS_M_AUTH.WORK_ID " +
",WFS_M_AUTH.LVL " +
",WFS_M_AUTH.ROUTE_ID " +
",WFS_M_AUTH.USR_GRP_ID " +
",WFS_T_WORKAPPROVALRES_CNT.CNT "
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
function selectWFS_T_WORKFLOW(_WORK_ID,_OBJECT_ID,_STEP) {
var sql =
"SELECT " +
" WORK_ID " +
", OBJECT_ID " +
", STEP " +
", OBJECT_NM " +
", ROUTE_ID " +
", USR_ID " +
", STATUS " +
", LVL " +
", APP_MEMO " +
", RES_MEMO " +
", REJECT_KBN " +
", CURENT_FLG " +
", CREATED_DATE " +
", CREATED_BY " +
", CREATED_PRG_NM " +
", UPDATED_DATE " +
", UPDATED_BY " +
", UPDATED_PRG_NM " +
", MODIFY_COUNT " +
"FROM WFS_T_WORKFLOW " +
"WHERE WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "'" +
" AND STEP = '" + tln_com_escape( _STEP ) + "'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
if ( TALON.getDbConfig().isPostgres() ) {
var itemColName_WFS_T_WORKFLOW = [
'work_id'
,'object_id'
,'step'
,'object_nm'
,'route_id'
,'usr_id'
,'status'
,'lvl'
,'app_memo'
,'res_memo'
,'curent_flg'
,'active_flg'
,'created_date'
,'created_by'
,'created_prg_nm'
,'updated_date'
,'updated_by'
,'updated_prg_nm'
,'modify_count'
];
} else {
var itemColName_WFS_T_WORKFLOW = [
'WORK_ID'
,'OBJECT_ID'
,'STEP'
,'OBJECT_NM'
,'ROUTE_ID'
,'USR_ID'
,'STATUS'
,'LVL'
,'APP_MEMO'
,'RES_MEMO'
,'CURENT_FLG'
,'ACTIVE_FLG'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
}
//-------------------------------------------
function insertWFS_T_WORKFLOW(itemDataList) {
setMapVal( itemDataList , 'CREATED_DATE' , tln_com_nowdate() );
setMapVal( itemDataList , 'CREATED_BY' , tln_com_user_id() );
setMapVal( itemDataList , 'CREATED_PRG_NM' , tln_com_func_id() );
setMapVal( itemDataList , 'UPDATED_DATE' , tln_com_nowdate() );
setMapVal( itemDataList , 'UPDATED_BY' , tln_com_user_id() );
setMapVal( itemDataList , 'UPDATED_PRG_NM' , tln_com_func_id() );
setMapVal( itemDataList , 'MODIFY_COUNT' , 1 );
setMapVal( itemDataList , 'ACTIVE_FLG' , '1' );
tln_insertByMap( 'WFS_T_WORKFLOW', itemDataList , itemColName_WFS_T_WORKFLOW );
}
//-------------------------------------------
function updateWFS_T_WORKFLOW(itemDataList) {
setMapVal( itemDataList , 'UPDATED_DATE' , tln_com_nowdate() );
setMapVal( itemDataList , 'UPDATED_BY' , tln_com_user_id() );
setMapVal( itemDataList , 'UPDATED_PRG_NM' , tln_com_func_id() );
setMapVal( itemDataList , 'MODIFY_COUNT' , 1 );
if ( TALON.getDbConfig().isPostgres() ) {
var whereTbl1 = [ null, '=' , 'work_id' ];
var whereTbl2 = [ null, '=' , 'object_id' ];
var whereTbl3 = [ null, '=' , 'step' ];
} else {
var whereTbl1 = [ null, '=' , 'WORK_ID' ];
var whereTbl2 = [ null, '=' , 'OBJECT_ID' ];
var whereTbl3 = [ null, '=' , 'STEP' ];
}
var whereList = new Array();
whereList.push(whereTbl1);
whereList.push(whereTbl2);
whereList.push(whereTbl3);
tln_updateByMap( 'WFS_T_WORKFLOW', itemDataList , itemColName_WFS_T_WORKFLOW , whereList );
}
//-------------------------------------------
function updateWFS_T_WORKFLOW_CURENT_FLG(_WORK_ID, _OBJECT_ID) {
TalonDbUtil.update( TALON.getDbConfig(), "update WFS_T_WORKFLOW set CURENT_FLG = '0' where WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' and OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "'" );
}
//-------------------------------------------
function updateWFS_T_WORKFLOW_ACTIVE_FLG(_WORK_ID, _OBJECT_ID, _TRG_LVL) {
TalonDbUtil.update( TALON.getDbConfig(),
"update WFS_T_WORKFLOW set ACTIVE_FLG = '0' " +
"where WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" and OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "'" +
" and LVL >= " + tln_com_escape( _TRG_LVL ) + ""
);
}
//-------------------------------------------
function selectWFS_T_WORKFLOW_CURENT_DATA(_WORK_ID,_OBJECT_ID) {
//承認者も取得する(連続承認者の時の承認省略に使用→and承認の場合は発動しない為MAXで取得)
var sql =
"SELECT " +
" COUNT(*) AS CURENT_DATA_CNT " +
" ,MAX(SHONIN_ID) AS SHONIN_ID " +
"FROM WFS_T_WORKFLOW " +
"WHERE WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "'" +
" AND CURENT_FLG = '1'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
function selectWFS_T_WORKFLOW_CURENT_MY_DATA(_WORK_ID,_OBJECT_ID,_EXEC_BY) {
var sql =
"SELECT " +
" COUNT(*) AS MY_DATA_CNT " +
"FROM WFS_T_WORKFLOW " +
"WHERE WORK_ID = '" + tln_com_escape( _WORK_ID ) + "'" +
" AND OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "'" +
" AND SHONIN_ID = '" + tln_com_escape( _EXEC_BY ) + "'" +
" AND CURENT_FLG = '1'" +
" AND STATUS <> '4'"
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
//取戻時、対象のレベルを取得
function selectWFS_T_WORKFLOW_MY_LVL_BACK(_WORK_ID,_ROUTE_ID,_NOW_LVL,_SHONIN_ID) {
var sql =
"SELECT " +
" WFS_M_AUTH.WORK_ID " +
" ,WFS_M_AUTH.ROUTE_ID " +
" ,MAX(WFS_M_AUTH.LVL) AS LVL " +
"FROM WFS_M_AUTH " +
"INNER JOIN WFS_M_USR_GRP_DEPDTL " +
" ON WFS_M_AUTH.USR_GRP_ID = WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " +
" AND ( " +
" WFS_M_USR_GRP_DEPDTL.USR_ID = '" + tln_com_escape( _SHONIN_ID ) + "' " +
" OR " +
" 1 = (SELECT CASE WHEN ADMIN_USER_ID IS NULL THEN 0 ELSE 1 END FROM WFS_M_USR_ADMIN WHERE ADMIN_USER_ID = '" + tln_com_escape( _SHONIN_ID ) + "' ) " +
" ) " +
"WHERE WFS_M_AUTH.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" AND WFS_M_AUTH.ROUTE_ID = '" + tln_com_escape( _ROUTE_ID ) + "' " +
" AND WFS_M_AUTH.LVL <= " + tln_com_escape( _NOW_LVL ) + " -1 " +
"GROUP BY " +
" WFS_M_AUTH.WORK_ID " +
" ,WFS_M_AUTH.ROUTE_ID "
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//引上げ時、対象のレベルを取得
function selectWFS_T_WORKFLOW_MY_LVL_PLUP(_WORK_ID,_ROUTE_ID,_NOW_LVL,_SHONIN_ID) {
var sql =
"SELECT " +
" WFS_M_AUTH.WORK_ID " +
" ,WFS_M_AUTH.ROUTE_ID " +
" ,MIN(WFS_M_AUTH.LVL) AS LVL " +
"FROM WFS_M_AUTH " +
"INNER JOIN WFS_M_USR_GRP_DEPDTL " +
" ON WFS_M_AUTH.USR_GRP_ID = WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " +
" AND ( " +
" WFS_M_USR_GRP_DEPDTL.USR_ID = '" + tln_com_escape( _SHONIN_ID ) + "' " +
" OR " +
" 1 = (SELECT CASE WHEN ADMIN_USER_ID IS NULL THEN 0 ELSE 1 END FROM WFS_M_USR_ADMIN WHERE ADMIN_USER_ID = '" + tln_com_escape( _SHONIN_ID ) + "' ) " +
" ) " +
"WHERE WFS_M_AUTH.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" AND WFS_M_AUTH.ROUTE_ID = '" + tln_com_escape( _ROUTE_ID ) + "' " +
" AND WFS_M_AUTH.LVL > " + tln_com_escape( _NOW_LVL ) + " " +
"GROUP BY " +
" WFS_M_AUTH.WORK_ID " +
" ,WFS_M_AUTH.ROUTE_ID "
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
//-------------------------------------------
//承認者連続時省略フラグ制御用、同一ルートで承認者が承認可能なリスト
function selectWFS_T_WORKFLOW_APPROVAL(_WORK_ID,_ROUTE_ID,_LVL,_SHONIN_ID, _OBJECT_ID, _LOGIN_USER_ID) {
//承認者も取得する(連続承認者の時の承認省略に使用→and承認の場合は発動しない為MAXで取得)
var sql =
"SELECT " +
" WFS_M_CONTROL.WORK_ID " +
" ,WFS_M_CONTROL.WORK_NM " +
" ,WFS_M_AUTH.ROUTE_ID " +
" ,WFS_M_AUTH.LVL " +
" ,WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " +
" ,WFS_M_USR_GRP_DEPDTL.USR_ID " +
" ,CASE WHEN WFS_M_LEVEL.SYONIN_PTN IS NOT NULL THEN WFS_M_LEVEL.SYONIN_PTN ELSE WFS_M_AUTH.SYONIN_PTN END AS SYONIN_PTN " +
"FROM WFS_M_CONTROL " +
"INNER JOIN WFS_M_AUTH " +
" ON WFS_M_CONTROL.WORK_ID = WFS_M_AUTH.WORK_ID " +
" AND '" + _ROUTE_ID + "' = WFS_M_AUTH.ROUTE_ID " +
" AND " + _LVL + " <= WFS_M_AUTH.LVL " +
"INNER JOIN WFS_M_USR_GRP_DEPDTL " +
" ON WFS_M_AUTH.USR_GRP_ID = WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " +
" AND '" + _SHONIN_ID + "' = WFS_M_USR_GRP_DEPDTL.USR_ID " +
"LEFT OUTER JOIN WFS_M_LEVEL " +
" ON WFS_M_AUTH.WORK_ID = WFS_M_LEVEL.WORK_ID " +
" AND WFS_M_AUTH.LVL = WFS_M_LEVEL.LVL " +
" " +
"LEFT OUTER JOIN ( " +
" SELECT " +
" WORK_ID " +
" ,OBJECT_ID " +
" ,LVL " +
" ,COUNT(*) AS CNT " +
" FROM WFS_T_WORKAPPROVALRES " +
" GROUP BY " +
" WORK_ID " +
" ,OBJECT_ID " +
" ,LVL " +
") WFS_T_WORKAPPROVALRES_CNT " +
" ON WFS_M_AUTH.WORK_ID = WFS_T_WORKAPPROVALRES_CNT.WORK_ID " +
" AND '" + _OBJECT_ID + "' = WFS_T_WORKAPPROVALRES_CNT.OBJECT_ID " +
" AND WFS_M_AUTH.LVL = WFS_T_WORKAPPROVALRES_CNT.LVL " +
" " +
"LEFT OUTER JOIN WFS_T_WORKAPPROVALRES " +
" ON WFS_M_AUTH.WORK_ID = WFS_T_WORKAPPROVALRES.WORK_ID " +
" AND '" + _OBJECT_ID + "' = WFS_T_WORKAPPROVALRES.OBJECT_ID " +
" AND WFS_M_AUTH.LVL = WFS_T_WORKAPPROVALRES.LVL " +
" AND WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_T_WORKAPPROVALRES.USR_ID " +
" AND ( " +
" WFS_T_WORKAPPROVALRES.USR_ID = '" + tln_com_escape( _LOGIN_USER_ID ) + "' " +
" OR " +
" WFS_T_WORKAPPROVALRES.USR_ID IN (SELECT USR_ID FROM WFS_M_USR_DAIRI WHERE DAIRI_USR_ID = '" + tln_com_escape( _LOGIN_USER_ID ) + "' AND YUKO_KBN = '1' AND SHONIN_FLG = '1') " +
" ) " +
" " +
"WHERE WFS_M_CONTROL.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" AND WFS_M_CONTROL.APPROVAL_FLG = '1' " +
" AND ( " +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NULL " +
" OR " +
" WFS_T_WORKAPPROVALRES_CNT.CNT = 0 " +
" OR " +
" ( " +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NOT NULL " +
" AND " +
" WFS_T_WORKAPPROVALRES.WORK_ID IS NOT NULL " +
" ) " +
" ) " +
"ORDER BY LVL "
;
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), sql);
return itemSelectList;
}
function updateWFS_T_WORKFLOW_STATUS(_WORK_ID, _OBJECT_ID, _STATUS, _STEP, _RES_MEMO, _SHONIN_ID) {
TalonDbUtil.update( TALON.getDbConfig(),
"update WFS_T_WORKFLOW set " +
" STATUS = '" + tln_com_escape( _STATUS ) + "' " +
" ,RES_MEMO = '" + tln_com_escape( _RES_MEMO ) + "' " +
" ,SHONIN_ID = '" + tln_com_escape( _SHONIN_ID ) + "' " +
"where WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" and OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "' " +
" and STEP = '" + tln_com_escape( _STEP ) + "' "
);
}
function execWorkFlow() {
//入力値取得
var itemBlockListHed = TALON.getBlockData_List(1);
var lineDataMap = itemBlockListHed[0];
return execWorkFlowMain(lineDataMap);
}
var _WFS_SYORI_KBN_SHINSEI = '10'; //申請
var _WFS_SYORI_KBN_SHONIN = '20'; //承認(次階層あり)
var _WFS_SYORI_KBN_KESSAI = '21'; //承認(次階層なし=決裁)
var _WFS_SYORI_KBN_SASHIMODOSHI = '30'; //差戻
var _WFS_SYORI_KBN_HININ = '90'; //否認
var _WFS_SYORI_KBN_TORIMODOSHIS = '50'; //取戻(申請者取戻)
var _WFS_SYORI_KBN_TORIKESHI = '60'; //取消
var _WFS_SYORI_KBN_TORIMODOSHIS = '70'; //取戻(承認者取戻)
var _WFS_SYORI_KBN_HIKIAGE = '80'; //引上
function execWorkFlowMain(lineDataMap) {
//入力値取得
//var itemBlockListHed = TALON.getBlockData_List(1);
//var lineDataMap = itemBlockListHed[0];
var lineUserDataMap = TALON.getUserInfoMap();
var _LOGIN_USER_ID = getMapVal( lineUserDataMap , 'USER_ID' );
//承認結果が申請の場合
if (getMapVal( lineDataMap , 'STATUS' ) == '1') {
//階層テーブルにて次のレベルが存在するかチェック
var itemSelectList = selectWFS_M_LEVEL_NEXTPRE( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'LVL' ), '1');
if (itemSelectList.length > 0) {
var lineSelectDataMap = itemSelectList[0];
var _NX_LVL = getMapVal( lineSelectDataMap , 'LVL' );
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ));
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _NX_LVL );
setMapVal( itemDataList , 'APP_MEMO' , getMapVal( lineDataMap , 'APP_MEMO' ) );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_SHINSEI);
}
}
//承認結果が取戻の場合(申請者が取り戻す)
if ( getMapVal( lineDataMap , 'STATUS' ) == '5' ) {
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
//申請者に戻すのでLVLが1以上のデータのACTIVE_FLGをゼロに更新(18/08/07)
updateWFS_T_WORKFLOW_ACTIVE_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID'), 1 );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , 1 );
setMapVal( itemDataList , 'APP_MEMO' , '' );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_TORIMODOSHIS);
}
//承認結果が取戻の場合(承認者が取り戻す)
if ( getMapVal( lineDataMap , 'STATUS' ) == '7' ) {
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
////取戻時、対象のレベルを取得
var itemSelectList = selectWFS_T_WORKFLOW_MY_LVL_BACK( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'LVL' ), tln_com_user_id() );
var lineSelectDataMap = itemSelectList[0];
var _MY_LVL = getMapVal( lineSelectDataMap , 'LVL' );
//指定したレベルまで戻すのでLVLがその値以上のデータのACTIVE_FLGをゼロに更新(18/08/07)
updateWFS_T_WORKFLOW_ACTIVE_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID'), _MY_LVL );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _MY_LVL );
setMapVal( itemDataList , 'APP_MEMO' , '' );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_TORIMODOSHIS);
}
//承認結果が引上げの場合(承認者が引き上げる)
if ( getMapVal( lineDataMap , 'STATUS' ) == '8' ) {
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
////引上時、対象のレベルを取得
var itemSelectList = selectWFS_T_WORKFLOW_MY_LVL_PLUP( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'LVL' ), tln_com_user_id() );
var lineSelectDataMap = itemSelectList[0];
var _MY_LVL = getMapVal( lineSelectDataMap , 'LVL' );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _MY_LVL );
setMapVal( itemDataList , 'APP_MEMO' , '' );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_HIKIAGE);
}
//承認、差戻、否認の処理で対象階層がAND承認の場合、すでに同一承認者で処理されていればエラーとする。
if (
( getMapVal( lineDataMap , 'STATUS' ) == '2') ||
( getMapVal( lineDataMap , 'STATUS' ) == '3') ||
( getMapVal( lineDataMap , 'STATUS' ) == '9')
) {
var itemSelectList = selectWFS_M_LEVEL( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'LVL' ), getMapVal( lineDataMap , 'ROUTE_ID' ) );
var lineSelectDataMap = itemSelectList[0];
var _SYONIN_PTN = getMapVal( lineSelectDataMap , 'SYONIN_PTN' );
if (_SYONIN_PTN == '2') {
//同一ユーザーで既に当サイクルで承認されている場合はエラーとする
//→同一ユーザーを同一承認者ID(SHONIN_ID)で判断するようにする
var itemSelectList = selectWFS_T_WORKFLOW_CURENT_MY_DATA( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ), getMapVal( lineDataMap , 'SHONIN_ID' ) );
var lineSelectDataMap = itemSelectList[0];
var _MY_DATA_CNT = getMapVal( lineSelectDataMap , 'MY_DATA_CNT' );
//ここまでの処理で1件は登録されている為
if ( _MY_DATA_CNT != 1 ) {
TALON.addErrorMsg( "既に指定された承認者で「承認/差戻/否認」処理が実施されている為、実行する事は出来ません。" );
TALON.setIsSuccess(false);
return false;
}
}
}
//承認結果が承認の場合
if ( getMapVal( lineDataMap , 'STATUS' ) == '2') {
var next_flg = '0';
var itemSelectList = selectWFS_M_LEVEL( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'LVL' ), getMapVal( lineDataMap , 'ROUTE_ID' ) );
var lineSelectDataMap = itemSelectList[0];
var _SYONIN_PTN = getMapVal( lineSelectDataMap , 'SYONIN_PTN' );
var itemSelectList = selectWFS_T_WORKFLOW_CURENT_DATA( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
var lineSelectDataMap = itemSelectList[0];
var _CURENT_DATA_CNT = getMapVal( lineSelectDataMap , 'CURENT_DATA_CNT' );
var _SHONIN_ID = getMapVal( lineSelectDataMap , 'SHONIN_ID' );
var itemSelectList = selectWFS_M_AUTH_TANTO_CNT( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'LVL' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
var lineSelectDataMap = itemSelectList[0];
var _TANTO_CNT = getMapVal( lineSelectDataMap , 'TANTO_CNT' );
if (_SYONIN_PTN == '1') {
next_flg = '1';
}
if (_SYONIN_PTN == '2') {
// * 上位でチェックするのでここでは実施しない
// * -------------------------------------------
// * //同一ユーザーで既に当サイクルで承認されている場合はエラーとする →同一ユーザーを同一承認者ID(SHONIN_ID)で判断するようにする
// * var lineUserDataMap = TALON.getUserInfoMap();
// * var _LOGIN_USER_ID = getMapVal( lineUserDataMap , 'USER_ID' );
// *
// * //var itemSelectList = selectWFS_T_WORKFLOW_CURENT_MY_DATA( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ), _LOGIN_USER_ID );
// * var itemSelectList = selectWFS_T_WORKFLOW_CURENT_MY_DATA( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ), getMapVal( lineDataMap , 'SHONIN_ID' ) );
// * var lineSelectDataMap = itemSelectList[0];
// * var _MY_DATA_CNT = getMapVal( lineSelectDataMap , 'MY_DATA_CNT' );
// *
// * //ここまでの処理で1件は登録されている為
// * if ( _MY_DATA_CNT != 1 ) {
// * TALON.addErrorMsg( "既に指定された承認者で「承認」処理が実施されている為、実行する事は出来ません。" );
// * TALON.setIsSuccess(false);
// *
// * return false;
// * }
if (_CURENT_DATA_CNT >= _TANTO_CNT) {
next_flg = '1';
}
}
if (next_flg == '1') {
//階層テーブルにて次のレベルが存在するかチェック
var itemSelectList = selectWFS_M_LEVEL_NEXTPRE( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'LVL' ), '1');
if (itemSelectList.length > 0) {
var lineSelectDataMap = itemSelectList[0];
var _NX_LVL = getMapVal( lineSelectDataMap , 'LVL' );
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _NX_LVL );
setMapVal( itemDataList , 'APP_MEMO' , getMapVal( lineDataMap , 'APP_MEMO' ) );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
//----------------------------------------------------------
// 以降の階層で今回の承認者が実施可能な階層を抽出
// OR承認の場合に発動
var _T_WORK_ID = getMapVal( lineDataMap , 'WORK_ID' );
var _T_OBJECT_ID = getMapVal( lineDataMap , 'OBJECT_ID' );
var _T_OBJECT_NM = getMapVal( lineDataMap , 'OBJECT_NM' );
var _T_ROUTE_ID = getMapVal( lineDataMap , 'ROUTE_ID' );
var _T_USR_ID = getMapVal( lineDataMap , 'USR_ID' );
var _T_APP_MEMO = getMapVal( lineDataMap , 'APP_MEMO' );
var _T_RES_MEMO = getMapVal( lineDataMap , 'RES_MEMO' );
var _T_STEP = parseInt( getMapVal( lineDataMap , 'STEP' ) + 1);
var _T_LVL = parseInt(_NX_LVL);
if (_SYONIN_PTN == '1') {
var itemSelectListApproval = selectWFS_T_WORKFLOW_APPROVAL( _T_WORK_ID, _T_ROUTE_ID, _NX_LVL, _SHONIN_ID, _T_OBJECT_ID, _LOGIN_USER_ID);
for (var i = 0; i < itemSelectListApproval.length; i++) {
var lineDataMap = itemSelectListApproval[i];
var _NOW_SYONIN_PTN = getMapVal( lineDataMap , 'SYONIN_PTN' );
if ( _T_LVL == parseInt( getMapVal( lineDataMap , 'LVL' ) ) && (_NOW_SYONIN_PTN == '1') ) {
//承認待ち階層にも承認者の権限あり
//上位で作成した承認待ちデータを承認済みに更新
//以下を更新
// ステータス=2承認
// 理由=入力値
// 承認者
updateWFS_T_WORKFLOW_STATUS( _T_WORK_ID, _T_OBJECT_ID, '2', _T_STEP , _T_RES_MEMO , _SHONIN_ID);
//階層テーブルにて次のレベルが存在するかチェック
var itemSelectList = selectWFS_M_LEVEL_NEXTPRE( _T_WORK_ID, _T_ROUTE_ID, _T_LVL, '1');
if (itemSelectList.length > 0) {
var lineSelectDataMap = itemSelectList[0];
var _NX_LVL = getMapVal( lineSelectDataMap , 'LVL' );
_T_STEP++;
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( _T_WORK_ID, _T_OBJECT_ID );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , _T_WORK_ID );
setMapVal( itemDataList , 'OBJECT_ID' , _T_OBJECT_ID );
setMapVal( itemDataList , 'STEP' , _T_STEP );
setMapVal( itemDataList , 'OBJECT_NM' , _T_OBJECT_NM );
setMapVal( itemDataList , 'ROUTE_ID' , _T_ROUTE_ID );
setMapVal( itemDataList , 'USR_ID' , _T_USR_ID );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _NX_LVL );
setMapVal( itemDataList , 'APP_MEMO' , _T_APP_MEMO );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
}
_T_LVL++;
} else {
//連続していないので終了
break;
}
}
}
//----------------------------------------------------------
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_SHONIN);
} else {
//決裁
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_KESSAI);
}
} else {
//同じ階層で 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID') );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM') );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , getMapVal( lineDataMap , 'LVL' ) );
setMapVal( itemDataList , 'APP_MEMO' , getMapVal( lineDataMap , 'APP_MEMO' ) );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
}
}
//承認結果が差戻の場合
if (getMapVal( lineDataMap , 'STATUS' ) == '3') {
//否決の動きが申請者に戻るか一つ前に戻るか確認
if (getMapVal( lineDataMap , 'REJECT_KBN' ) == '1') {
//申請者に戻る場合
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID') );
//申請者に戻すのでLVLが1以上のデータのACTIVE_FLGをゼロに更新(18/08/07)
updateWFS_T_WORKFLOW_ACTIVE_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID'), 1 );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID' ) );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM' ) );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , 1 );
setMapVal( itemDataList , 'APP_MEMO' , '' );
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_SASHIMODOSHI);
}
if (getMapVal( lineDataMap , 'REJECT_KBN' ) == '2') {
//ひとつ前に戻る場合
//階層テーブルにて前のレベルが存在するかチェック
var itemSelectList = selectWFS_M_LEVEL_NEXTPRE( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'ROUTE_ID' ), getMapVal( lineDataMap , 'LVL' ), '2');
if (itemSelectList.length > 0) {
var lineSelectDataMap = itemSelectList[0];
var _NX_LVL = getMapVal( lineSelectDataMap , 'LVL' );
//次期対象以外のCURENT_FLGを0に更新
updateWFS_T_WORKFLOW_CURENT_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ) );
//申請者に戻すのでLVLが一つ前の値以上のデータのACTIVE_FLGをゼロに更新(18/08/07)
updateWFS_T_WORKFLOW_ACTIVE_FLG( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID'), _NX_LVL );
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID') );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
setMapVal( itemDataList , 'OBJECT_NM' , getMapVal( lineDataMap , 'OBJECT_NM') );
setMapVal( itemDataList , 'ROUTE_ID' , getMapVal( lineDataMap , 'ROUTE_ID' ) );
setMapVal( itemDataList , 'USR_ID' , getMapVal( lineDataMap , 'USR_ID' ) );
setMapVal( itemDataList , 'STATUS' , '4' );
setMapVal( itemDataList , 'LVL' , _NX_LVL );
if (_NX_LVL == 1) {
setMapVal( itemDataList , 'APP_MEMO' , '' );
} else {
setMapVal( itemDataList , 'APP_MEMO' , getMapVal( lineDataMap , 'APP_MEMO' ) );
}
setMapVal( itemDataList , 'CURENT_FLG' , '1' );
insertWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_SASHIMODOSHI);
}
}
}
//承認結果が否認の場合(当処理としては何もしない(上位TALONで実施済み)
if ( getMapVal( lineDataMap , 'STATUS' ) == '9' ) {
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_HININ);
}
return true;
}
function execWorkFlowStop() {
//入力値取得
var itemBlockListHed = TALON.getBlockData_List(1);
var lineDataMap = itemBlockListHed[0];
//次ステップのデータが
//存在する場合はエラーとする
var itemSelectList = selectWFS_T_WORKFLOW( getMapVal( lineDataMap , 'WORK_ID' ), getMapVal( lineDataMap , 'OBJECT_ID' ), ( getMapVal( lineDataMap , 'STEP' ) + 1 ) );
if (itemSelectList.length > 0) {
TALON.addErrorMsg( "既に処理が行われている為、中止処理を実施できません" );
TALON.setIsSuccess(false);
} else {
//データありの場合のみ 次レコード作成
var itemDataList = new Array();
setMapVal( itemDataList , 'WORK_ID' , getMapVal( lineDataMap , 'WORK_ID' ) );
setMapVal( itemDataList , 'OBJECT_ID' , getMapVal( lineDataMap , 'OBJECT_ID') );
setMapVal( itemDataList , 'STEP' , parseInt( getMapVal( lineDataMap , 'STEP' ) ) );
setMapVal( itemDataList , 'STATUS' , '6' );
updateWFS_T_WORKFLOW(itemDataList);
execWorkFlowCustom(getMapVal( lineDataMap , 'WORK_ID' ) , getMapVal( lineDataMap , 'OBJECT_ID' ) , _WFS_SYORI_KBN_TORIKESHI);
TALON.addMsg( "中止処理を実施しました" );
TALON.setIsSuccess(true);
}
}
function _mail_data_wfs(_WORK_ID, _STEP, _OBJECT_ID) {
var mailData = {};
mailData.WFS_SUBJ = null;
mailData.WFS_MAIL = null;
mailData.WFS_MLTEXT = null;
var sql = "" +
"SELECT " +
" " +
" BASE.WORK_ID " +
",BASE.WORK_NM " +
",BASE.STEP " +
",BASE.OBJECT_ID " +
",BASE.USR_ID " +
",BASE.MAIL_ADD AS MAIL " +
" " +
",REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" BASE.MAIL_TITLE, " +
" '%1_STEP%', " +
" concat(BASE.STEP ,'') " +
" ), " +
" '%1_OBJECT_NM%', " +
" case when BASE.OBJECT_NM is null then '' else BASE.OBJECT_NM end " +
" ), " +
" '%1_WORK_ID%', " +
" BASE.WORK_ID " +
" ), " +
" '%1_WORK_NM%', " +
" case when BASE.WORK_NM is null then '' else BASE.WORK_NM end " +
" ), " +
" '%1_OBJECT_ID%', " +
" BASE.OBJECT_ID " +
" ), " +
" '%1_RES_MEMO%', " +
" case when BASE.RES_MEMO is null then '' else BASE.RES_MEMO end " +
" ) AS SUBJ " +
" " +
" " +
",REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" BASE.MAIL_TEXT, " +
" '%1_STEP%', " +
" concat(BASE.STEP ,'') " +
" ), " +
" '%1_OBJECT_NM%', " +
" case when BASE.OBJECT_NM is null then '' else BASE.OBJECT_NM end " +
" ), " +
" '%1_WORK_ID%', " +
" BASE.WORK_ID " +
" ), " +
" '%1_WORK_NM%', " +
" case when BASE.WORK_NM is null then '' else BASE.WORK_NM end " +
" ), " +
" '%1_OBJECT_ID%', " +
" BASE.OBJECT_ID " +
" ), " +
" '%1_RES_MEMO%', " +
" case when BASE.RES_MEMO is null then '' else BASE.RES_MEMO end " +
" ) AS MLTEXT " +
" " +
"FROM ( " +
" SELECT " +
" " +
" WFS_T_WORKFLOW.WORK_ID " +
" ,WFS_M_CONTROL.WORK_NM " +
" ,WFS_T_WORKFLOW.STEP " +
" ,WFS_T_WORKFLOW.OBJECT_ID " +
" ,WFS_T_WORKFLOW.OBJECT_NM " +
" ,WFS_T_WORKFLOW.USR_ID " +
" ,WFS_T_WORKFLOW.LVL " +
" ,WFS_T_WORKFLOW.ROUTE_ID " +
" ,WFS_T_WORKFLOW.STATUS " +
" ,WFS_T_WORKFLOW.RES_MEMO " +
" " +
" ,CASE " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NULL AND WFS_T_WORKFLOW.STATUS = '2' THEN '決裁' " +
" WHEN WFS_T_WORKFLOW.LVL = '1' THEN '再申請' " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NOT NULL AND (WFS_T_WORKFLOW.STATUS = '1' or WFS_T_WORKFLOW.STATUS = '2') THEN '承認' " +
" WHEN WFS_T_WORKFLOW.LVL <> '1' AND WFS_T_WORKFLOW.STATUS = '3' THEN '否認' " +
" END AS EXEC_FLG " +
" " +
" ,CASE " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NULL AND WFS_T_WORKFLOW.STATUS = '2' THEN " +
" TLN_CONCAT( " +
" WFS_ALL_MAIL(WFS_M_AUTH_FT.USR_GRP_ID, WFS_T_WORKFLOW.USR_ID ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_FT.LVL), " +
" CASE WHEN WFS_M_ROUTE_HED.END_SEND_MAIL IS NULL THEN '' ELSE WFS_M_ROUTE_HED.END_SEND_MAIL END , " +
" ',' " +
" ) " +
" WHEN WFS_T_WORKFLOW.LVL = '1' THEN WFS_ALL_MAIL(WFS_M_AUTH_NX.USR_GRP_ID, NULL ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_NX.LVL) " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NOT NULL AND (WFS_T_WORKFLOW.STATUS = '1' or WFS_T_WORKFLOW.STATUS = '2') THEN WFS_ALL_MAIL(WFS_M_AUTH_NX.USR_GRP_ID, NULL ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_NX.LVL) " +
" WHEN WFS_T_WORKFLOW.LVL <> '1' AND WFS_T_WORKFLOW_NX.LVL <> '1' AND WFS_T_WORKFLOW.STATUS = '3' THEN WFS_ALL_MAIL(WFS_M_AUTH_NX.USR_GRP_ID, NULL ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_NX.LVL) " +
" WHEN WFS_T_WORKFLOW.LVL <> '1' AND WFS_T_WORKFLOW_NX.LVL = '1' AND WFS_T_WORKFLOW.STATUS = '3' THEN WFS_ALL_MAIL(WFS_M_AUTH_FT.USR_GRP_ID, WFS_T_WORKFLOW.USR_ID ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_FT.LVL) " +
" WHEN WFS_T_WORKFLOW.STATUS = '9' THEN WFS_ALL_MAIL(WFS_M_AUTH_FT.USR_GRP_ID, WFS_T_WORKFLOW.USR_ID ,WFS_T_WORKFLOW.WORK_ID ,WFS_T_WORKFLOW.OBJECT_ID ,WFS_M_AUTH_FT.LVL) " +
" END AS MAIL_ADD " +
" " +
" ,CASE " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NULL AND WFS_T_WORKFLOW.STATUS = '2' THEN WFS_M_CONTROL.MAIL_TITLE_KESSAI " +
" WHEN WFS_T_WORKFLOW.LVL = '1' THEN WFS_M_CONTROL.MAIL_TITLE_SINSEI " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NOT NULL AND (WFS_T_WORKFLOW.STATUS = '1' or WFS_T_WORKFLOW.STATUS = '2') THEN WFS_M_CONTROL.MAIL_TITLE_SYONIN " +
" WHEN WFS_T_WORKFLOW.LVL <> '1' AND WFS_T_WORKFLOW.STATUS = '3' THEN WFS_M_CONTROL.MAIL_TITLE_HININ " +
" WHEN WFS_T_WORKFLOW.STATUS = '9' THEN WFS_M_CONTROL.MAIL_TITLE_HININ2 " +
" END AS MAIL_TITLE " +
" " +
" ,CASE " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NULL AND WFS_T_WORKFLOW.STATUS = '2' THEN WFS_M_CONTROL.MAIL_TEXT_KESSAI " +
" WHEN WFS_T_WORKFLOW.LVL = '1' THEN WFS_M_CONTROL.MAIL_TEXT_SINSEI " +
" WHEN WFS_T_WORKFLOW_NX.WORK_ID IS NOT NULL AND (WFS_T_WORKFLOW.STATUS = '1' or WFS_T_WORKFLOW.STATUS = '2') THEN WFS_M_CONTROL.MAIL_TEXT_SYONIN " +
" WHEN WFS_T_WORKFLOW.LVL <> '1' AND WFS_T_WORKFLOW.STATUS = '3' THEN WFS_M_CONTROL.MAIL_TEXT_HININ " +
" WHEN WFS_T_WORKFLOW.STATUS = '9' THEN WFS_M_CONTROL.MAIL_TEXT_HININ2 " +
" END AS MAIL_TEXT " +
" " +
" FROM WFS_T_WORKFLOW " +
" " +
" INNER JOIN WFS_M_CONTROL " +
" ON WFS_M_CONTROL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " +
" " +
" LEFT OUTER JOIN WFS_T_WORKFLOW WFS_T_WORKFLOW_NX " +
" ON WFS_T_WORKFLOW.WORK_ID = WFS_T_WORKFLOW_NX.WORK_ID " +
" AND WFS_T_WORKFLOW.OBJECT_ID = WFS_T_WORKFLOW_NX.OBJECT_ID " +
" AND WFS_T_WORKFLOW.STEP + 1 = WFS_T_WORKFLOW_NX.STEP " +
" " +
" LEFT OUTER JOIN WFS_M_AUTH WFS_M_AUTH_NX " +
" ON WFS_T_WORKFLOW_NX.WORK_ID = WFS_M_AUTH_NX.WORK_ID " +
" AND WFS_T_WORKFLOW_NX.LVL = WFS_M_AUTH_NX.LVL " +
" AND WFS_T_WORKFLOW_NX.ROUTE_ID = WFS_M_AUTH_NX.ROUTE_ID " +
" " +
" LEFT OUTER JOIN WFS_T_WORKFLOW WFS_T_WORKFLOW_FT " +
" ON WFS_T_WORKFLOW.WORK_ID = WFS_T_WORKFLOW_FT.WORK_ID " +
" AND WFS_T_WORKFLOW.OBJECT_ID = WFS_T_WORKFLOW_FT.OBJECT_ID " +
" AND 1 = WFS_T_WORKFLOW_FT.STEP " +
" " +
" LEFT OUTER JOIN WFS_M_AUTH WFS_M_AUTH_FT " +
" ON WFS_T_WORKFLOW_FT.WORK_ID = WFS_M_AUTH_FT.WORK_ID " +
" AND WFS_T_WORKFLOW_FT.LVL = WFS_M_AUTH_FT.LVL " +
" AND WFS_T_WORKFLOW_FT.ROUTE_ID = WFS_M_AUTH_FT.ROUTE_ID " +
" " +
" LEFT OUTER JOIN WFS_M_ROUTE_HED " +
" ON WFS_T_WORKFLOW.ROUTE_ID = WFS_M_ROUTE_HED.ROUTE_ID " +
" " +
" WHERE WFS_T_WORKFLOW.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" AND WFS_T_WORKFLOW.STEP = '" + tln_com_escape( _STEP ) + "' " +
" AND WFS_T_WORKFLOW.OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "' " +
" " +
") BASE " +
" ";
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
if (itemSelectList.length > 0) {
var lineDataMap = itemSelectList[0];
mailData.WFS_SUBJ = getMapVal( lineDataMap , 'SUBJ' );
mailData.WFS_MAIL = getMapVal( lineDataMap , 'MAIL' );
mailData.WFS_MLTEXT = getMapVal( lineDataMap , 'MLTEXT' );
}
return mailData;
}
function _mail_data_reminder(_WORK_ID, _STEP, _OBJECT_ID) {
var mailData = {};
mailData.WFS_SUBJ = null;
mailData.WFS_MAIL = null;
mailData.WFS_MLTEXT = null;
var sql = "" +
"SELECT " +
" " +
" BASE.WORK_ID " +
",BASE.WORK_NM " +
",BASE.STEP as STEP " +
",BASE.REMINDER_ID " +
" " +
",BASE.OBJECT_ID " +
",BASE.USR_ID " +
",BASE.MAIL_ADD AS MAIL " +
" " +
",REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" BASE.MAIL_TITLE, " +
" '%1_STEP%', " +
" concat(BASE.STEP ,'') " +
" ), " +
" '%1_OBJECT_NM%', " +
" case when BASE.OBJECT_NM is null then '' else BASE.OBJECT_NM end " +
" ), " +
" '%1_WORK_ID%', " +
" BASE.WORK_ID " +
" ), " +
" '%1_WORK_NM%', " +
" case when BASE.WORK_NM is null then '' else BASE.WORK_NM end " +
" ), " +
" '%1_OBJECT_ID%', " +
" BASE.OBJECT_ID " +
" ), " +
" '%1_RES_MEMO%', " +
" case when BASE.RES_MEMO is null then '' else BASE.RES_MEMO end " +
" ) AS SUBJ " +
" " +
",REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" REPLACE( " +
" BASE.MAIL_TEXT, " +
" '%1_STEP%', " +
" concat(BASE.STEP ,'') " +
" ), " +
" '%1_OBJECT_NM%', " +
" case when BASE.OBJECT_NM is null then '' else BASE.OBJECT_NM end " +
" ), " +
" '%1_WORK_ID%', " +
" BASE.WORK_ID " +
" ), " +
" '%1_WORK_NM%', " +
" case when BASE.WORK_NM is null then '' else BASE.WORK_NM end " +
" ), " +
" '%1_OBJECT_ID%', " +
" BASE.OBJECT_ID " +
" ), " +
" '%1_RES_MEMO%', " +
" case when BASE.RES_MEMO is null then '' else BASE.RES_MEMO end " +
" ) AS MLTEXT " +
" " +
"FROM ( " +
" " +
" SELECT " +
" WFS_T_WORKREMINDER.WORK_ID " +
" ,WFS_M_CONTROL.WORK_NM " +
" ,WFS_T_WORKREMINDER.STEP " +
" ,WFS_T_WORKREMINDER.OBJECT_ID " +
" ,WFS_T_WORKFLOW.OBJECT_NM " +
" ,WFS_T_WORKREMINDER.REMINDER_ID " +
" ,WFS_T_WORKFLOW.USR_ID " +
" ,WFS_T_WORKFLOW.LVL " +
" ,WFS_T_WORKFLOW.ROUTE_ID " +
" ,WFS_T_WORKFLOW.STATUS " +
" ,WFS_T_WORKREMINDER.RES_MEMO " +
" " +
" ,WFS_ALL_MAIL(WFS_M_AUTH.USR_GRP_ID, NULL , WFS_T_WORKREMINDER.WORK_ID , WFS_T_WORKREMINDER.OBJECT_ID , WFS_M_AUTH.LVL) AS MAIL_ADD " +
" " +
" ,WFS_M_CONTROL.MAIL_TITLE_SAISOKU AS MAIL_TITLE " +
" " +
" ,WFS_M_CONTROL.MAIL_TEXT_SAISOKU AS MAIL_TEXT " +
" " +
" FROM WFS_T_WORKREMINDER " +
" " +
" INNER JOIN WFS_T_WORKFLOW " +
" ON WFS_T_WORKREMINDER.WORK_ID = WFS_T_WORKFLOW.WORK_ID " +
" AND WFS_T_WORKREMINDER.OBJECT_ID = WFS_T_WORKFLOW.OBJECT_ID " +
" AND WFS_T_WORKREMINDER.STEP = WFS_T_WORKFLOW.STEP " +
" " +
" INNER JOIN WFS_M_CONTROL " +
" ON WFS_M_CONTROL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " +
" " +
" LEFT OUTER JOIN WFS_M_AUTH WFS_M_AUTH " +
" ON WFS_T_WORKFLOW.WORK_ID = WFS_M_AUTH.WORK_ID " +
" AND WFS_T_WORKFLOW.LVL = WFS_M_AUTH.LVL " +
" AND WFS_T_WORKFLOW.ROUTE_ID = WFS_M_AUTH.ROUTE_ID " +
" " +
" WHERE WFS_T_WORKFLOW.WORK_ID = '" + tln_com_escape( _WORK_ID ) + "' " +
" AND WFS_T_WORKFLOW.STEP = '" + tln_com_escape( _STEP ) + "' " +
" AND WFS_T_WORKFLOW.OBJECT_ID = '" + tln_com_escape( _OBJECT_ID ) + "' " +
" " +
") BASE " +
" ";
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig() , sql );
if (itemSelectList.length > 0) {
var lineDataMap = itemSelectList[itemSelectList.length - 1]; // STEPが進行しないまま複数回の催促が起こり得るため、最後の催促内容をメール送信する
mailData.WFS_SUBJ = getMapVal( lineDataMap , 'SUBJ' );
mailData.WFS_MAIL = getMapVal( lineDataMap , 'MAIL' );
mailData.WFS_MLTEXT = getMapVal( lineDataMap , 'MLTEXT' );
}
return mailData;
}
≣ サーバJS ライブラリWFS_CUSTOM [共通]ワークフローシステム(ユーザー処理用) 1504字
/**
* WFS_CUSTOM : [共通]ワークフローシステム(ユーザー処理用)
*
* @version 2019/03/01
*/
//-------------------------------------------------------
// パラメータ
// work_id ワークフローID
// object_id オブジェクトID
// syori_kbn 処理区分
// 10 : 申請 [ STATUS = 1 ]
// 20 : 承認(次階層あり) [ STATUS = 2 ]
// 21 : 承認(次階層なし=決裁) [ STATUS = 2 ]
// 30 : 差戻 [ STATUS = 3 ]
// 90 : 否認 [ STATUS = 9 ]
// 50 : 取戻(申請者取戻) [ STATUS = 5 ]
// 60 : 取消 [ STATUS = 6 ]
// 70 : 取戻(承認者取戻) [ STATUS = 7 ]
// 80 : 引上 [ STATUS = 8 ]
//-------------------------------------------------------
var _WFS_SYORI_KBN_SHINSEI = '10'; //申請
var _WFS_SYORI_KBN_SHONIN = '20'; //承認(次階層あり)
var _WFS_SYORI_KBN_KESSAI = '21'; //承認(次階層なし=決裁)
var _WFS_SYORI_KBN_SASHIMODOSHI = '30'; //差戻
var _WFS_SYORI_KBN_HININ = '90'; //否認
var _WFS_SYORI_KBN_TORIMODOSHIS = '50'; //取戻(申請者取戻)
var _WFS_SYORI_KBN_TORIKESHI = '60'; //取消
var _WFS_SYORI_KBN_TORIMODOSHIS = '70'; //取戻(承認者取戻)
var _WFS_SYORI_KBN_HIKIAGE = '80'; //引上
function execWorkFlowCustom(work_id , obj_id , syori_kbn) {
var status = '';
var table = '';
var join = '';
var param = '';
switch (work_id) {
//(WORK_ID:XXXXXXXXXX)
case 'XXXXXXXXXX':
break;
//(WORK_ID:XXXXXXXXXX)
case 'XXXXXXXXXX':
break;
default:
break;
}
}
≣ サーバJS ライブラリWFS_SETUP [共通]ワークフローシステム(環境構築) 144200字
/**
* WFS_SETUP : [共通]ワークフローシステム(環境構築)
*
* 最終更新:WFS_2_0_2
* @version 2023/11/13
*/
//--------------------------------------------
// セットアップ関連共通
//--------------------------------------------
function table_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_TABLES WHERE TABLE_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM information_schema.tables WHERE table_name = '" + nm + "' AND table_schema = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'U' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(DISTINCT table_name) AS CNT FROM information_schema.columns WHERE LOWER(table_name) = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function function_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_PROCEDURES WHERE OBJECT_TYPE = 'FUNCTION' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA = '" + _DSP1 + "' AND SPECIFIC_NAME = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'FN' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_proc WHERE proname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function view_exists(nm) {
if ( TALON.getDbConfig().isOra() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM USER_OBJECTS WHERE OBJECT_TYPE = 'VIEW' AND OBJECT_NAME = '" + nm + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
}
if ( TALON.getDbConfig().isMy() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT DSP1 FROM TLN_M_HANYO_CODE_MAIN WHERE SIKIBETU_CODE='TLN_GENERAL' AND KEY_CODE='DB_NAME'" );
var lineDataMap = itemSelectList[0];
var _DSP1 = getMapVal(lineDataMap,'DSP1');
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '" + nm + "' AND TABLE_SCHEMA = '" + _DSP1 + "' " );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isMssql() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM sys.objects WHERE type = 'V' AND name = '" + nm + "'" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if ( TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM pg_class WHERE relkind = 'v' and relname = LOWER('" + nm + "')" );
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
};
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function field_exists(nm,fl) {
if ( !TALON.getDbConfig().isPostgres() ) {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = '" + nm + "' AND COLUMN_NAME = '" + fl + "' " );
} else {
var itemSelectList = TalonDbUtil.select( TALON.getDbConfig(), "SELECT COUNT(*) AS CNT FROM TLN_M_NAME_MANAGER WHERE TABLE_NAME = LOWER('" + nm + "') AND COLUMN_NAME = LOWER('" + fl + "') " );
}
var lineDataMap = itemSelectList[0];
var _CNT = getMapVal(lineDataMap,'CNT');
if (_CNT == 0) {
return false;
} else {
return true;
}
}
function executeSQL(sql) {
if ( TALON.getDbConfig().isOra() ) {
//Oracleの場合true
TALON.executeSQL(sql);
};
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
if ( TALON.getDbConfig().isPostgres() ) {
//Postgresの場合true
TalonDbUtil.update( TALON.getDbConfig(), sql);
};
}
function table_exists_drop(nm) {
if (table_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP TABLE " + nm ) ;
} else {
executeSQL( "DROP TABLE " + nm.toLowerCase() ) ;
}
}
}
function function_exists_drop(nm) {
if (function_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP FUNCTION " + nm ) ;
} else {
executeSQL( "DROP FUNCTION " + nm.toLowerCase() ) ;
}
}
}
function view_exists_drop(nm) {
if (view_exists(nm)) {
if ( !TALON.getDbConfig().isPostgres() ) {
executeSQL( "DROP VIEW " + nm ) ;
} else {
executeSQL( "DROP VIEW " + nm.toLowerCase() ) ;
}
}
}
//--------------------------------------------
// セットアップ後環境別データ修正
//--------------------------------------------
function exec_custom() {
if ( TALON.getDbConfig().isMy() ) {
//MySQLの場合true
if ( chkLowercase() ) {
//lowercaseとして判断
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_KBN = 'UPDATE_TABLE' AND FUNC_ID LIKE 'WFS_%' ");
}
}
if ( TALON.getDbConfig().isMssql() ) {
//MsSqlServerの場合true
var array = ["TLN_DATE_TO_CHAR","TLN_CHAR_TO_DATE","TLN_SYSDATE","TLN_CONCAT","TLN_CHARINDEX","TLN_CHAR_TO_NUMBER","WFS_ALL_MAIL","WFS_AUTH_MAIN","WFS_AUTH_SHINSEI","WFS_AUTH_SHONIN","WFS_WF_EXISTS","WFS_WF_STEP"];
var i;
var num = array.length;
for(i=0;i < num;i++){
//--------------
//TLN_M_GENERAL_FUNC_SQL
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_FUNC_SQL " +
" SET " +
" BODY_SQL = REPLACE(REPLACE(BODY_SQL ,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" ,TITLE_SQL = REPLACE(REPLACE(TITLE_SQL,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'WFS_%' "
);
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_GENERAL_ITEM_OPTN " +
" SET " +
" CHR_TEXT = REPLACE(REPLACE(CHR_TEXT,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_ID <> 'WFS_M000' " +
" AND (FUNC_KBN = 'JAVA_SCRIPT_ENGINE' OR (FUNC_KBN = 'BUTTON_BAT' AND FLAG = 2)) "
);
//--------------
//TLN_M_HANYO_CODE_MAIN
TalonDbUtil.update( TALON.getDbConfig(),
" UPDATE TLN_M_HANYO_CODE_MAIN " +
" SET " +
" NOTE = REPLACE(REPLACE(NOTE,'" + array[i] + "','dbo." + array[i] + "'),'dbo.dbo.','dbo.') " +
" WHERE SIKIBETU_CODE = 'TLN_GENERAL_JAVASCRIPT_ENGINE' " +
" AND KEY_CODE <> 'WFS_SETUP' "
);
}
}
if ( TALON.getDbConfig().isPostgres() ) {
//PostgreSQLの場合true
//lower
//--------------
//TLN_M_GENERAL_ITEM
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_ID <> 'WFS_M000' ");
//--------------
//TLN_M_GENERAL_FUNC_SQL
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = LOWER(BODY_SQL) WHERE FUNC_ID LIKE 'WFS_%' ");
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET TITLE_SQL = LOWER(TITLE_SQL) WHERE FUNC_ID LIKE 'WFS_%' ");
// *
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'tln_login_user','TLN_LOGIN_USER') WHERE FUNC_ID LIKE 'WFS_%' ");
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'wfs_all_chk' ,'WFS_ALL_CHK' ) WHERE FUNC_ID LIKE 'WFS_%' ");
// *
// * WFS_M034のみバインド変数を小文字化
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%WORK_ID%**/' ,'/**%work_id%**/' ) WHERE FUNC_ID LIKE 'WFS_M034' ");
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%WORK_NM%**/' ,'/**%work_nm%**/' ) WHERE FUNC_ID LIKE 'WFS_M034' ");
// * TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%ROUTE_ID%**/' ,'/**%route_id%**/' ) WHERE FUNC_ID LIKE 'WFS_M034' ");
//機能内で使用しているバインド変数を小文字に変換
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%APP_MEMO_SEL%**/' ,'/**%app_memo_sel%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%ID%**/' ,'/**%id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%JOB_ID%**/' ,'/**%job_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%LVL%**/' ,'/**%lvl%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%NOT_END_FLG%**/' ,'/**%not_end_flg%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%OBJECT_ID%**/' ,'/**%object_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%OBJECT_NM%**/' ,'/**%object_nm%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%PARAM_CTL_UMU%**/' ,'/**%param_ctl_umu%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%PARAM_TRG%**/' ,'/**%param_trg%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%ROUTE_ID%**/' ,'/**%route_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%SEL_CHK_NO%**/' ,'/**%sel_chk_no%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%SEL_DEL_FLG%**/' ,'/**%sel_del_flg%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%SEL_WORK_ID%**/' ,'/**%sel_work_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%TENKAI_HOUKOU%**/' ,'/**%tenkai_houkou%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%USR_ID%**/' ,'/**%usr_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%WORK_ID%**/' ,'/**%work_id%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_FUNC_SQL SET BODY_SQL = REPLACE(BODY_SQL,'/**%WORK_NM%**/' ,'/**%work_nm%**/' ) WHERE FUNC_ID LIKE 'WFS_%' ");
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = LOWER(CHR4) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace(CHR4,'sample_work01','SAMPLE_WORK01') WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR4 = replace(CHR4,'sample_work02','SAMPLE_WORK02') WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'BUTTON_NEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND), CHR1 = LOWER(CHR1), CHR_TEXT = LOWER(CHR_TEXT), CHR4 = LOWER(CHR4) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'SEND_MAIL' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) WHERE FUNC_ID LIKE 'WFS_%' AND ( FUNC_KBN LIKE 'BUTTON_NEXT_%' or FUNC_KBN = 'INPUT_CONDITION' ) ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1), CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'WFS_%' AND ( FUNC_KBN = 'SUB_SEARCH' OR FUNC_KBN = 'LOOK_UP' ) ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'REGIST_VALUE' AND CHR1 NOT LIKE '%WFS%' AND CHR1 NOT LIKE '%SYSDATE%' AND CHR1 NOT LIKE '%LOGIN_ID%' AND CHR1 NOT LIKE '%TLN_M%'"); //システムバインド変数、機能ID、URLはそのまま
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'REGIST_VALUE' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET KIND = LOWER(KIND) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'MATCH_PATTERN' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) , CHR2 = LOWER(CHR2) , CHR3 = LOWER(CHR3) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'SUGGEST' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'FORE_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'INIT_VALUE_TEXT' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'OTHER_FUNC' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = LOWER(CHR1), CHR3 = LOWER(CHR3) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN LIKE 'OTHER_FUNC_%' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR3 = replace(CHR3,'%login_id%','%LOGIN_ID%') WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN LIKE 'OTHER_FUNC_%' "); //他機能呼出のシステム変数は大文字
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR2 = LOWER(CHR2) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'BACK_COLOR' ");
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET CHR1 = REPLACE(CHR1,'%2_ROUTE_SET_KBN_NULL%' ,'%2_route_set_kbn_null%' ) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'REGIST_VALUE' ");
//--------------
//TLN_M_GENERAL_ITEM_OPTN
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_ITEM_OPTN SET COL_NAME = LOWER(COL_NAME) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN NOT IN ('SEND_MAIL' , 'OTHER_FUNC' , 'JAVA_SCRIPT_ENGINE' , 'JAVA_SCRIPT' , 'BUTTON_NEXT' , 'BUTTON_BAT' , 'BUTTON_DSP_POS' ) AND FUNC_KBN NOT LIKE 'BUTTON_AJAX%' ");
//TLN_M_GENERAL_APP
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_APP SET VALUE = LOWER(VALUE) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_KBN = 'UPDATE_TABLE' ");
//TLN_M_GENERAL_USES
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_USES SET KEY_CODE = LOWER(KEY_CODE) WHERE FUNC_ID LIKE 'WFS_%' AND USER_CODE = 'TLN_GEN_ALL' ");
//--------------
//TLN_M_GENERAL_POSITION
TalonDbUtil.update( TALON.getDbConfig(), " UPDATE TLN_M_GENERAL_POSITION SET NAME = LOWER(NAME) WHERE FUNC_ID LIKE 'WFS_%' AND FUNC_ID <> 'WFS_M000' AND CHR1='ITEM' ");
}
}
//--------------------------------------------
// Ver1.4へのバージョンアップ
//--------------------------------------------
function exec_ver_up_14( _func_chk ){
//テーブルの追加
exec_ver_up_14_TableModify();
//データのパッチ(補填)
exec_ver_up_patch_14_DataPatch();
//画面でファンクションの再構築が設定された場合(初回インストールは固定1で呼び出される)
if ( _func_chk == '1' ) {
//ファンクションの再構築 →ファンクション・Viewはパッチ毎に最新を作成
exec_create_Function();
//Viewの再構築 →ファンクション・Viewはパッチ毎に最新を作成
exec_create_View();
}
}
function exec_ver_up_14_TableModify(){
//テーブル変更、追加処理
//------------------------------
if ( TALON.getDbConfig().isOra() ) {
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_AUTH','SYONIN_PTN')) {
executeSQL(
"ALTER TABLE WFS_M_AUTH ADD ( " +
"SYONIN_PTN VARCHAR2(20) NULL " +
")" +
"");
}
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_CONTROL','APPROVAL_FLG')) {
executeSQL(
"ALTER TABLE WFS_M_CONTROL MODIFY ( " +
"MAIL_TEXT_KESSAI VARCHAR2(3000) , " +
"MAIL_TEXT_SINSEI VARCHAR2(3000) , " +
"MAIL_TEXT_SYONIN VARCHAR2(3000) , " +
"MAIL_TEXT_HININ VARCHAR2(3000) " +
")" +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL ADD ( " +
"APPROVAL_FLG VARCHAR2(20) NULL , " +
"ROUTE_SET_KBN VARCHAR2(50) NULL , " +
"ROUTE_STRUCT_ID VARCHAR2(50) NULL , " +
"MAIL_TITLE_HININ2 VARCHAR2(100) NULL , " +
"MAIL_TEXT_HININ2 VARCHAR2(3000) NULL , " +
"MAIL_TITLE_SAISOKU VARCHAR2(100) NULL , " +
"MAIL_TEXT_SAISOKU VARCHAR2(3000) NULL , " +
"CATEGORY_ID VARCHAR2(50) NULL " +
")" +
"");
}
//--------------------------------------
//[変更]WFS_M_ROUTE_HED
if (!field_exists('WFS_M_ROUTE_HED','PARAM_FM')) {
executeSQL(
"ALTER TABLE WFS_M_ROUTE_HED ADD ( " +
"PARAM_FM VARCHAR2(50) NULL , " +
"PARAM_VAL VARCHAR2(100) NULL , " +
"PARAM_TP VARCHAR2(50) NULL , " +
"END_SEND_MAIL VARCHAR2(100) NULL , " +
"DEL_FLG VARCHAR2(10) NULL " +
")" +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_HED
if (!table_exists('WFS_M_STRUCT_HED')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_HED " + "\n" +
" (" + "\n" +
" ID VARCHAR2(50) NOT NULL," + "\n" +
" TITLE VARCHAR2(100) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_HED " + "\n" +
" ADD ( CONSTRAINT PK_WFS_M_STRUCT_HED PRIMARY KEY (ID) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_DTL
if (!table_exists('WFS_M_STRUCT_DTL')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_DTL " + "\n" +
" (" + "\n" +
" ID VARCHAR2(50) NOT NULL," + "\n" +
" SEQ NUMBER(10) NOT NULL," + "\n" +
" CHILD_ID VARCHAR2(50) ," + "\n" +
" OYA_ID VARCHAR2(50) ," + "\n" +
" BOTTOM_FLG VARCHAR2(10) ," + "\n" +
" SYONIN_PTN VARCHAR2(20) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_DTL " + "\n" +
" ADD ( CONSTRAINT PK_WFS_M_STRUCT_DTL PRIMARY KEY (ID, SEQ) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_TEMP
if (!table_exists('WFS_W_STRUCT_TEMP')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_TEMP " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR2(50) NOT NULL," + "\n" +
" ID VARCHAR2(50) ," + "\n" +
" SEQ NUMBER(10) NOT NULL," + "\n" +
" CHILD_ID VARCHAR2(50) ," + "\n" +
" OYA_ID VARCHAR2(50) ," + "\n" +
" BOTTOM_FLG VARCHAR2(10) ," + "\n" +
" SYONIN_PTN VARCHAR2(20) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_TEMP " + "\n" +
" ADD ( CONSTRAINT PK_WFS_W_STRUCT_TEMP PRIMARY KEY (JOB_ID, SEQ) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_LIST
if (!table_exists('WFS_W_STRUCT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_LIST " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR2(50) NOT NULL," + "\n" +
" ID VARCHAR2(50) ," + "\n" +
" SEQ NUMBER(10) NOT NULL," + "\n" +
" SORT VARCHAR2(50) ," + "\n" +
" LVL VARCHAR2(10) ," + "\n" +
" OYA_ID VARCHAR2(50) ," + "\n" +
" CHILD_ID VARCHAR2(50) ," + "\n" +
" SYONIN_PTN VARCHAR2(20) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_LIST " + "\n" +
" ADD ( CONSTRAINT PK_WFS_W_STRUCT_LIST PRIMARY KEY (JOB_ID, SEQ) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[変更]WFS_T_WORKFLOW
if (!field_exists('WFS_T_WORKFLOW','SHONIN_ID')) {
executeSQL(
"ALTER TABLE WFS_T_WORKFLOW ADD ( " +
"SHONIN_ID VARCHAR2(100) NULL , " +
"ACTIVE_FLG VARCHAR2(20) NULL , " +
"HOLD_FLG VARCHAR2(20) NULL " +
")" +
"");
}
//--------------------------------------
//[新規]WFS_W_STAT_LIST
if (!table_exists('WFS_W_STAT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STAT_LIST " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR2(100) NOT NULL ," + "\n" +
" OBJECT_ID VARCHAR2(100) NOT NULL ," + "\n" +
" LVL01_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL01_DT DATE DEFAULT NULL ," + "\n" +
" LVL01_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL02_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL02_DT DATE DEFAULT NULL ," + "\n" +
" LVL02_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL03_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL03_DT DATE DEFAULT NULL ," + "\n" +
" LVL03_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL04_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL04_DT DATE DEFAULT NULL ," + "\n" +
" LVL04_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL05_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL05_DT DATE DEFAULT NULL ," + "\n" +
" LVL05_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL06_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL06_DT DATE DEFAULT NULL ," + "\n" +
" LVL06_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL07_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL07_DT DATE DEFAULT NULL ," + "\n" +
" LVL07_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL08_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL08_DT DATE DEFAULT NULL ," + "\n" +
" LVL08_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL09_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL09_DT DATE DEFAULT NULL ," + "\n" +
" LVL09_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL10_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL10_DT DATE DEFAULT NULL ," + "\n" +
" LVL10_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL11_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL11_DT DATE DEFAULT NULL ," + "\n" +
" LVL11_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL12_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL12_DT DATE DEFAULT NULL ," + "\n" +
" LVL12_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL13_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL13_DT DATE DEFAULT NULL ," + "\n" +
" LVL13_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL14_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL14_DT DATE DEFAULT NULL ," + "\n" +
" LVL14_US VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL15_NM VARCHAR2(100) DEFAULT NULL ," + "\n" +
" LVL15_DT DATE DEFAULT NULL ," + "\n" +
" LVL15_US VARCHAR2(100) DEFAULT NULL " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STAT_LIST " + "\n" +
" ADD ( CONSTRAINT PK_WFS_W_STAT_LIST PRIMARY KEY (WORK_ID, OBJECT_ID) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_USR_DAIRI
if (!table_exists('WFS_M_USR_DAIRI')) {
executeSQL(
" CREATE TABLE WFS_M_USR_DAIRI " + "\n" +
" (" + "\n" +
" USR_ID VARCHAR2(100) NOT NULL," + "\n" +
" DAIRI_USR_ID VARCHAR2(100) NOT NULL," + "\n" +
" SHINSEI_FLG VARCHAR2(10) ," + "\n" +
" SHONIN_FLG VARCHAR2(10) ," + "\n" +
" YUKO_KBN VARCHAR2(10) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_USR_DAIRI " + "\n" +
" ADD ( CONSTRAINT PK_WFS_M_USR_DAIRI PRIMARY KEY (USR_ID, DAIRI_USR_ID) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKREMINDER
if (!table_exists('WFS_T_WORKREMINDER')) {
executeSQL(
" CREATE TABLE WFS_T_WORKREMINDER " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR2(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR2(100) NOT NULL," + "\n" +
" STEP DECIMAL(10,0) NOT NULL," + "\n" +
" REMINDER_ID VARCHAR2(100) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR2(100) ," + "\n" +
" LVL DECIMAL(10,0) ," + "\n" +
" RES_MEMO VARCHAR2(4000) ," + "\n" +
" SEND_ADDRESS VARCHAR2(500) ," + "\n" +
" SEND_TITLE VARCHAR2(500) ," + "\n" +
" SEND_TEXT VARCHAR2(4000) ," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKREMINDER " + "\n" +
" ADD ( CONSTRAINT PK_WFS_T_WORKREMINDER PRIMARY KEY (WORK_ID, OBJECT_ID, STEP, REMINDER_ID) USING INDEX ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKAPPROVALRES
if (!table_exists('WFS_T_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR2(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR2(100) NOT NULL," + "\n" +
" LVL DECIMAL(10,0) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR2(100) ," + "\n" +
" USR_GRP_ID VARCHAR2(100) ," + "\n" +
" USR_ID VARCHAR2(100) NOT NULL," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" ADD ( CONSTRAINT PK_WFS_T_WORKAPPROVALRES PRIMARY KEY (WORK_ID, OBJECT_ID, LVL, USR_ID) USING INDEX ) " + "\n" +
"");
}
}
if ( TALON.getDbConfig().isMy() ) {
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_AUTH','SYONIN_PTN')) {
executeSQL(
"ALTER TABLE WFS_M_AUTH " +
"ADD COLUMN SYONIN_PTN VARCHAR(20) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_CONTROL','APPROVAL_FLG')) {
executeSQL(
"ALTER TABLE WFS_M_CONTROL " +
"CHANGE COLUMN MAIL_TEXT_KESSAI MAIL_TEXT_KESSAI TEXT NULL DEFAULT NULL , " +
"CHANGE COLUMN MAIL_TEXT_SINSEI MAIL_TEXT_SINSEI TEXT NULL DEFAULT NULL , " +
"CHANGE COLUMN MAIL_TEXT_SYONIN MAIL_TEXT_SYONIN TEXT NULL DEFAULT NULL , " +
"CHANGE COLUMN MAIL_TEXT_HININ MAIL_TEXT_HININ TEXT NULL DEFAULT NULL , " +
"ADD COLUMN APPROVAL_FLG VARCHAR(20) NULL , " +
"ADD COLUMN ROUTE_SET_KBN VARCHAR(50) NULL , " +
"ADD COLUMN ROUTE_STRUCT_ID VARCHAR(50) NULL , " +
"ADD COLUMN MAIL_TITLE_HININ2 VARCHAR(100) NULL , " +
"ADD COLUMN MAIL_TEXT_HININ2 TEXT NULL , " +
"ADD COLUMN MAIL_TITLE_SAISOKU VARCHAR(100) NULL , " +
"ADD COLUMN MAIL_TEXT_SAISOKU TEXT NULL , " +
"ADD COLUMN CATEGORY_ID VARCHAR(50) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_ROUTE_HED
if (!field_exists('WFS_M_ROUTE_HED','PARAM_FM')) {
executeSQL(
"ALTER TABLE WFS_M_ROUTE_HED " +
"ADD COLUMN PARAM_FM VARCHAR(50) NULL , " +
"ADD COLUMN PARAM_VAL VARCHAR(100) NULL , " +
"ADD COLUMN PARAM_TP VARCHAR(50) NULL , " +
"ADD COLUMN END_SEND_MAIL VARCHAR(100) NULL , " +
"ADD COLUMN DEL_FLG VARCHAR(10) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_HED
if (!table_exists('WFS_M_STRUCT_HED')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_HED " + "\n" +
" (" + "\n" +
" ID VARCHAR(50) NOT NULL," + "\n" +
" TITLE VARCHAR(100) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_HED " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_DTL
if (!table_exists('WFS_M_STRUCT_DTL')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_DTL " + "\n" +
" (" + "\n" +
" ID VARCHAR(50) NOT NULL," + "\n" +
" SEQ INT(10) NOT NULL," + "\n" +
" CHILD_ID VARCHAR(50) ," + "\n" +
" OYA_ID VARCHAR(50) ," + "\n" +
" BOTTOM_FLG VARCHAR(10) ," + "\n" +
" SYONIN_PTN VARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_DTL " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (ID, SEQ)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_TEMP
if (!table_exists('WFS_W_STRUCT_TEMP')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_TEMP " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR(50) NOT NULL," + "\n" +
" ID VARCHAR(50) ," + "\n" +
" SEQ INT(10) NOT NULL," + "\n" +
" CHILD_ID VARCHAR(50) ," + "\n" +
" OYA_ID VARCHAR(50) ," + "\n" +
" BOTTOM_FLG VARCHAR(10) ," + "\n" +
" SYONIN_PTN VARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_TEMP " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (JOB_ID, SEQ)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_LIST
if (!table_exists('WFS_W_STRUCT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_LIST " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR(50) NOT NULL," + "\n" +
" ID VARCHAR(50) ," + "\n" +
" SEQ INT(10) NOT NULL," + "\n" +
" SORT VARCHAR(50) ," + "\n" +
" LVL VARCHAR(10) ," + "\n" +
" OYA_ID VARCHAR(50) ," + "\n" +
" CHILD_ID VARCHAR(50) ," + "\n" +
" SYONIN_PTN VARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_LIST " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (JOB_ID, SEQ)" + "\n" +
"");
}
//--------------------------------------
//[変更]WFS_T_WORKFLOW
if (!field_exists('WFS_T_WORKFLOW','SHONIN_ID')) {
executeSQL(
"ALTER TABLE WFS_T_WORKFLOW " +
"ADD COLUMN SHONIN_ID VARCHAR(100) NULL , " +
"ADD COLUMN ACTIVE_FLG VARCHAR(20) NULL , " +
"ADD COLUMN HOLD_FLG VARCHAR(20) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_W_STAT_LIST
if (!table_exists('WFS_W_STAT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STAT_LIST " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR(100) NOT NULL ," + "\n" +
" OBJECT_ID VARCHAR(100) NOT NULL ," + "\n" +
" LVL01_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL01_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL01_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL02_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL02_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL02_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL03_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL03_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL03_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL04_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL04_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL04_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL05_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL05_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL05_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL06_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL06_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL06_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL07_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL07_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL07_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL08_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL08_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL08_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL09_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL09_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL09_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL10_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL10_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL10_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL11_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL11_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL11_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL12_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL12_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL12_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL13_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL13_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL13_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL14_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL14_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL14_US VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL15_NM VARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL15_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL15_US VARCHAR(100) DEFAULT NULL " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STAT_LIST " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (WORK_ID, OBJECT_ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_USR_DAIRI
if (!table_exists('WFS_M_USR_DAIRI')) {
executeSQL(
" CREATE TABLE WFS_M_USR_DAIRI " + "\n" +
" (" + "\n" +
" USR_ID VARCHAR(100) NOT NULL," + "\n" +
" DAIRI_USR_ID VARCHAR(100) NOT NULL," + "\n" +
" SHINSEI_FLG VARCHAR(10) ," + "\n" +
" SHONIN_FLG VARCHAR(10) ," + "\n" +
" YUKO_KBN VARCHAR(10) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_USR_DAIRI " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (USR_ID, DAIRI_USR_ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKREMINDER
if (!table_exists('WFS_T_WORKREMINDER')) {
executeSQL(
" CREATE TABLE WFS_T_WORKREMINDER " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR(100) NOT NULL," + "\n" +
" STEP DECIMAL(10,0) NOT NULL," + "\n" +
" REMINDER_ID VARCHAR(100) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR(100) ," + "\n" +
" LVL DECIMAL(10,0) ," + "\n" +
" RES_MEMO VARCHAR(4000) ," + "\n" +
" SEND_ADDRESS VARCHAR(500) ," + "\n" +
" SEND_TITLE VARCHAR(500) ," + "\n" +
" SEND_TEXT VARCHAR(4000) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKREMINDER " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (WORK_ID, OBJECT_ID, STEP, REMINDER_ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKAPPROVALRES
if (!table_exists('WFS_T_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" WORK_ID VARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR(100) NOT NULL," + "\n" +
" LVL DECIMAL(10,0) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR(100) ," + "\n" +
" USR_GRP_ID VARCHAR(100) ," + "\n" +
" USR_ID VARCHAR(100) NOT NULL," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (WORK_ID, OBJECT_ID, LVL, USR_ID)" + "\n" +
"");
}
};
if ( TALON.getDbConfig().isMssql() ) {
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_AUTH','SYONIN_PTN')) {
executeSQL(
"ALTER TABLE WFS_M_AUTH ADD " +
"SYONIN_PTN NVARCHAR(20) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_CONTROL','APPROVAL_FLG')) {
executeSQL(
"ALTER TABLE WFS_M_CONTROL ALTER COLUMN MAIL_TEXT_KESSAI NVARCHAR(3000) ; " +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL ALTER COLUMN MAIL_TEXT_SINSEI NVARCHAR(3000) ; " +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL ALTER COLUMN MAIL_TEXT_SYONIN NVARCHAR(3000) ; " +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL ALTER COLUMN MAIL_TEXT_HININ NVARCHAR(3000) ; " +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL ADD " +
"APPROVAL_FLG NVARCHAR(20) NULL , " +
"ROUTE_SET_KBN NVARCHAR(50) NULL , " +
"ROUTE_STRUCT_ID NVARCHAR(50) NULL , " +
"MAIL_TITLE_HININ2 NVARCHAR(100) NULL , " +
"MAIL_TEXT_HININ2 NVARCHAR(3000) NULL , " +
"MAIL_TITLE_SAISOKU NVARCHAR(100) NULL , " +
"MAIL_TEXT_SAISOKU NVARCHAR(3000) NULL , " +
"CATEGORY_ID NVARCHAR(50) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_ROUTE_HED
if (!field_exists('WFS_M_ROUTE_HED','PARAM_FM')) {
executeSQL(
"ALTER TABLE WFS_M_ROUTE_HED ADD " +
"PARAM_FM NVARCHAR(50) NULL , " +
"PARAM_VAL NVARCHAR(100) NULL , " +
"PARAM_TP NVARCHAR(50) NULL , " +
"END_SEND_MAIL NVARCHAR(100) NULL , " +
"DEL_FLG NVARCHAR(10) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_HED
if (!table_exists('WFS_M_STRUCT_HED')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_HED " + "\n" +
" (" + "\n" +
" ID NVARCHAR(50) NOT NULL," + "\n" +
" TITLE NVARCHAR(100) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_HED " + "\n" +
" ADD CONSTRAINT PK_WFS_M_STRUCT_HED PRIMARY KEY NONCLUSTERED (ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_DTL
if (!table_exists('WFS_M_STRUCT_DTL')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_DTL " + "\n" +
" (" + "\n" +
" ID NVARCHAR(50) NOT NULL," + "\n" +
" SEQ NUMERIC(10) NOT NULL," + "\n" +
" CHILD_ID NVARCHAR(50) ," + "\n" +
" OYA_ID NVARCHAR(50) ," + "\n" +
" BOTTOM_FLG NVARCHAR(10) ," + "\n" +
" SYONIN_PTN NVARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_DTL " + "\n" +
" ADD CONSTRAINT PK_WFS_M_STRUCT_DTL PRIMARY KEY NONCLUSTERED (ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_TEMP
if (!table_exists('WFS_W_STRUCT_TEMP')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_TEMP " + "\n" +
" (" + "\n" +
" JOB_ID NVARCHAR(50) NOT NULL," + "\n" +
" ID NVARCHAR(50) ," + "\n" +
" SEQ NUMERIC(10) NOT NULL," + "\n" +
" CHILD_ID NVARCHAR(50) ," + "\n" +
" OYA_ID NVARCHAR(50) ," + "\n" +
" BOTTOM_FLG NVARCHAR(10) ," + "\n" +
" SYONIN_PTN NVARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_TEMP " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STRUCT_TEMP PRIMARY KEY NONCLUSTERED (JOB_ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_LIST
if (!table_exists('WFS_W_STRUCT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_LIST " + "\n" +
" (" + "\n" +
" JOB_ID NVARCHAR(50) NOT NULL," + "\n" +
" ID NVARCHAR(50) ," + "\n" +
" SEQ NUMERIC(10) NOT NULL," + "\n" +
" SORT NVARCHAR(50) ," + "\n" +
" LVL NVARCHAR(10) ," + "\n" +
" OYA_ID NVARCHAR(50) ," + "\n" +
" CHILD_ID NVARCHAR(50) ," + "\n" +
" SYONIN_PTN NVARCHAR(20) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_LIST " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STRUCT_LIST PRIMARY KEY NONCLUSTERED (JOB_ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[変更]WFS_T_WORKFLOW
if (!field_exists('WFS_T_WORKFLOW','SHONIN_ID')) {
executeSQL(
"ALTER TABLE WFS_T_WORKFLOW ADD " +
"SHONIN_ID NVARCHAR(100) NULL , " +
"ACTIVE_FLG NVARCHAR(20) NULL , " +
"HOLD_FLG NVARCHAR(20) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_W_STAT_LIST
if (!table_exists('WFS_W_STAT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STAT_LIST " + "\n" +
" (" + "\n" +
" WORK_ID NVARCHAR(100) NOT NULL ," + "\n" +
" OBJECT_ID NVARCHAR(100) NOT NULL ," + "\n" +
" LVL01_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL01_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL01_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL02_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL02_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL02_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL03_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL03_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL03_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL04_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL04_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL04_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL05_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL05_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL05_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL06_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL06_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL06_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL07_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL07_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL07_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL08_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL08_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL08_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL09_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL09_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL09_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL10_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL10_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL10_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL11_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL11_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL11_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL12_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL12_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL12_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL13_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL13_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL13_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL14_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL14_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL14_US NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL15_NM NVARCHAR(100) DEFAULT NULL ," + "\n" +
" LVL15_DT DATETIME DEFAULT NULL ," + "\n" +
" LVL15_US NVARCHAR(100) DEFAULT NULL " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STAT_LIST " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STAT_LIST PRIMARY KEY NONCLUSTERED (WORK_ID, OBJECT_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_USR_DAIRI
if (!table_exists('WFS_M_USR_DAIRI')) {
executeSQL(
" CREATE TABLE WFS_M_USR_DAIRI " + "\n" +
" (" + "\n" +
" USR_ID NVARCHAR(100) NOT NULL," + "\n" +
" DAIRI_USR_ID NVARCHAR(100) NOT NULL," + "\n" +
" SHINSEI_FLG NVARCHAR(10) ," + "\n" +
" SHONIN_FLG NVARCHAR(10) ," + "\n" +
" YUKO_KBN NVARCHAR(10) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_USR_DAIRI " + "\n" +
" ADD CONSTRAINT PK_WFS_M_USR_DAIRI PRIMARY KEY NONCLUSTERED (USR_ID, DAIRI_USR_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKREMINDER
if (!table_exists('WFS_T_WORKREMINDER')) {
executeSQL(
" CREATE TABLE WFS_T_WORKREMINDER " + "\n" +
" (" + "\n" +
" WORK_ID NVARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID NVARCHAR(100) NOT NULL," + "\n" +
" STEP NUMERIC(10,0) NOT NULL," + "\n" +
" REMINDER_ID NVARCHAR(100) NOT NULL," + "\n" +
" ROUTE_ID NVARCHAR(100) ," + "\n" +
" LVL NUMERIC(10,0) ," + "\n" +
" RES_MEMO NVARCHAR(4000) ," + "\n" +
" SEND_ADDRESS NVARCHAR(500) ," + "\n" +
" SEND_TITLE NVARCHAR(500) ," + "\n" +
" SEND_TEXT NVARCHAR(4000) ," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKREMINDER " + "\n" +
" ADD CONSTRAINT PK_WFS_T_WORKREMINDER PRIMARY KEY NONCLUSTERED (WORK_ID, OBJECT_ID, STEP, REMINDER_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKAPPROVALRES
if (!table_exists('WFS_T_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" WORK_ID NVARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID NVARCHAR(100) NOT NULL," + "\n" +
" LVL NUMERIC(10,0) NOT NULL," + "\n" +
" ROUTE_ID NVARCHAR(100) ," + "\n" +
" USR_GRP_ID NVARCHAR(100) ," + "\n" +
" USR_ID NVARCHAR(100) NOT NULL," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PK_WFS_T_WORKAPPROVALRES PRIMARY KEY NONCLUSTERED (WORK_ID, OBJECT_ID, LVL, USR_ID) " + "\n" +
"");
}
};
if ( TALON.getDbConfig().isPostgres() ) {
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_AUTH','SYONIN_PTN')) {
executeSQL(
"ALTER TABLE WFS_M_AUTH " +
"ADD SYONIN_PTN character varying(20) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_CONTROL
if (!field_exists('WFS_M_CONTROL','APPROVAL_FLG')) {
executeSQL(
"ALTER TABLE WFS_M_CONTROL " +
"ALTER COLUMN MAIL_TEXT_KESSAI TYPE character varying(3000) , " +
"ALTER COLUMN MAIL_TEXT_SINSEI TYPE character varying(3000) , " +
"ALTER COLUMN MAIL_TEXT_SYONIN TYPE character varying(3000) , " +
"ALTER COLUMN MAIL_TEXT_HININ TYPE character varying(3000) " +
"");
executeSQL(
"ALTER TABLE WFS_M_CONTROL " +
"ADD APPROVAL_FLG character varying(20) NULL , " +
"ADD ROUTE_SET_KBN character varying(50) NULL , " +
"ADD ROUTE_STRUCT_ID character varying(50) NULL , " +
"ADD MAIL_TITLE_HININ2 character varying(100) NULL , " +
"ADD MAIL_TEXT_HININ2 character varying(3000) NULL , " +
"ADD MAIL_TITLE_SAISOKU character varying(100) NULL , " +
"ADD MAIL_TEXT_SAISOKU character varying(3000) NULL , " +
"ADD CATEGORY_ID character varying(50) NULL " +
"");
}
//--------------------------------------
//[変更]WFS_M_ROUTE_HED
if (!field_exists('WFS_M_ROUTE_HED','PARAM_FM')) {
executeSQL(
"ALTER TABLE WFS_M_ROUTE_HED " +
"ADD PARAM_FM character varying(50) NULL , " +
"ADD PARAM_VAL character varying(100) NULL , " +
"ADD PARAM_TP character varying(50) NULL , " +
"ADD END_SEND_MAIL character varying(100) NULL , " +
"ADD DEL_FLG character varying(10) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_HED
if (!table_exists('WFS_M_STRUCT_HED')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_HED " + "\n" +
" (" + "\n" +
" ID character varying(50) NOT NULL," + "\n" +
" TITLE character varying(100) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_HED " + "\n" +
" ADD CONSTRAINT PK_WFS_M_STRUCT_HED PRIMARY KEY (ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_STRUCT_DTL
if (!table_exists('WFS_M_STRUCT_DTL')) {
executeSQL(
" CREATE TABLE WFS_M_STRUCT_DTL " + "\n" +
" (" + "\n" +
" ID character varying(50) NOT NULL," + "\n" +
" SEQ numeric(10,0) NOT NULL," + "\n" +
" CHILD_ID character varying(50) ," + "\n" +
" OYA_ID character varying(50) ," + "\n" +
" BOTTOM_FLG character varying(10) ," + "\n" +
" SYONIN_PTN character varying(20) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_STRUCT_DTL " + "\n" +
" ADD CONSTRAINT PK_WFS_M_STRUCT_DTL PRIMARY KEY (ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_TEMP
if (!table_exists('WFS_W_STRUCT_TEMP')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_TEMP " + "\n" +
" (" + "\n" +
" JOB_ID character varying(50) NOT NULL," + "\n" +
" ID character varying(50) ," + "\n" +
" SEQ numeric(10,0) NOT NULL," + "\n" +
" CHILD_ID character varying(50) ," + "\n" +
" OYA_ID character varying(50) ," + "\n" +
" BOTTOM_FLG character varying(10) ," + "\n" +
" SYONIN_PTN character varying(20) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_TEMP " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STRUCT_TEMP PRIMARY KEY (JOB_ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_STRUCT_LIST
if (!table_exists('WFS_W_STRUCT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STRUCT_LIST " + "\n" +
" (" + "\n" +
" JOB_ID character varying(50) NOT NULL," + "\n" +
" ID character varying(50) ," + "\n" +
" SEQ numeric(10,0) NOT NULL," + "\n" +
" SORT character varying(50) ," + "\n" +
" LVL character varying(10) ," + "\n" +
" OYA_ID character varying(50) ," + "\n" +
" CHILD_ID character varying(50) ," + "\n" +
" SYONIN_PTN character varying(20) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STRUCT_LIST " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STRUCT_LIST PRIMARY KEY (JOB_ID, SEQ) " + "\n" +
"");
}
//--------------------------------------
//[変更]WFS_T_WORKFLOW
if (!field_exists('WFS_T_WORKFLOW','SHONIN_ID')) {
executeSQL(
"ALTER TABLE WFS_T_WORKFLOW " +
"ADD SHONIN_ID character varying(100) NULL , " +
"ADD ACTIVE_FLG character varying(20) NULL , " +
"ADD HOLD_FLG character varying(20) NULL " +
"");
}
//--------------------------------------
//[新規]WFS_W_STAT_LIST
if (!table_exists('WFS_W_STAT_LIST')) {
executeSQL(
" CREATE TABLE WFS_W_STAT_LIST " + "\n" +
" (" + "\n" +
" WORK_ID character varying(100) NOT NULL ," + "\n" +
" OBJECT_ID character varying(100) NOT NULL ," + "\n" +
" LVL01_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL01_DT timestamp DEFAULT NULL ," + "\n" +
" LVL01_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL02_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL02_DT timestamp DEFAULT NULL ," + "\n" +
" LVL02_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL03_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL03_DT timestamp DEFAULT NULL ," + "\n" +
" LVL03_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL04_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL04_DT timestamp DEFAULT NULL ," + "\n" +
" LVL04_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL05_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL05_DT timestamp DEFAULT NULL ," + "\n" +
" LVL05_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL06_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL06_DT timestamp DEFAULT NULL ," + "\n" +
" LVL06_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL07_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL07_DT timestamp DEFAULT NULL ," + "\n" +
" LVL07_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL08_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL08_DT timestamp DEFAULT NULL ," + "\n" +
" LVL08_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL09_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL09_DT timestamp DEFAULT NULL ," + "\n" +
" LVL09_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL10_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL10_DT timestamp DEFAULT NULL ," + "\n" +
" LVL10_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL11_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL11_DT timestamp DEFAULT NULL ," + "\n" +
" LVL11_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL12_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL12_DT timestamp DEFAULT NULL ," + "\n" +
" LVL12_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL13_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL13_DT timestamp DEFAULT NULL ," + "\n" +
" LVL13_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL14_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL14_DT timestamp DEFAULT NULL ," + "\n" +
" LVL14_US character varying(100) DEFAULT NULL ," + "\n" +
" LVL15_NM character varying(100) DEFAULT NULL ," + "\n" +
" LVL15_DT timestamp DEFAULT NULL ," + "\n" +
" LVL15_US character varying(100) DEFAULT NULL " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_STAT_LIST " + "\n" +
" ADD CONSTRAINT PK_WFS_W_STAT_LIST PRIMARY KEY (WORK_ID, OBJECT_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_M_USR_DAIRI
if (!table_exists('WFS_M_USR_DAIRI')) {
executeSQL(
" CREATE TABLE WFS_M_USR_DAIRI " + "\n" +
" (" + "\n" +
" USR_ID character varying(100) NOT NULL," + "\n" +
" DAIRI_USR_ID character varying(100) NOT NULL," + "\n" +
" SHINSEI_FLG character varying(10) ," + "\n" +
" SHONIN_FLG character varying(10) ," + "\n" +
" YUKO_KBN character varying(10) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_M_USR_DAIRI " + "\n" +
" ADD CONSTRAINT PK_WFS_M_USR_DAIRI PRIMARY KEY (USR_ID, DAIRI_USR_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKREMINDER
if (!table_exists('WFS_T_WORKREMINDER')) {
executeSQL(
" CREATE TABLE WFS_T_WORKREMINDER " + "\n" +
" (" + "\n" +
" WORK_ID character varying(100) NOT NULL," + "\n" +
" OBJECT_ID character varying(100) NOT NULL," + "\n" +
" STEP numeric(10,0) NOT NULL," + "\n" +
" REMINDER_ID character varying(100) NOT NULL," + "\n" +
" ROUTE_ID character varying(100) ," + "\n" +
" LVL numeric(10,0) ," + "\n" +
" RES_MEMO character varying(4000) ," + "\n" +
" SEND_ADDRESS character varying(500) ," + "\n" +
" SEND_TITLE character varying(500) ," + "\n" +
" SEND_TEXT character varying(4000) ," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKREMINDER " + "\n" +
" ADD CONSTRAINT PK_WFS_T_WORKREMINDER PRIMARY KEY (WORK_ID, OBJECT_ID, STEP, REMINDER_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_T_WORKAPPROVALRES
if (!table_exists('WFS_T_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" WORK_ID character varying(100) NOT NULL," + "\n" +
" OBJECT_ID character varying(100) NOT NULL," + "\n" +
" LVL numeric(10,0) NOT NULL," + "\n" +
" ROUTE_ID character varying(100) ," + "\n" +
" USR_GRP_ID character varying(100) ," + "\n" +
" USR_ID character varying(100) NOT NULL," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_T_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PK_WFS_T_WORKAPPROVALRES PRIMARY KEY (WORK_ID, OBJECT_ID, LVL, USR_ID) " + "\n" +
"");
}
};
}
function exec_ver_up_patch_14_DataPatch(){
//データパッチ処理 : バージョンアップに伴いデータ修正が必要となった際のパッチ処理
//------------------------------
// WFS_T_WORKFLOW の ACTIVE_FLG
// function patch_WORKFLOW_ACTIVE_FLG()
//-------
var sql = "" +
"SELECT WORK_ID , OBJECT_ID FROM WFS_T_WORKFLOW " +
"WHERE ACTIVE_FLG IS NULL " +
"GROUP BY WORK_ID , OBJECT_ID ";
var itemSelectListMain = TalonDbUtil.select( TALON.getDbConfig(), sql );
for (var i = 0; i < itemSelectListMain.length; i++) {
var lineDataMap = itemSelectListMain[i];
var _WORK_ID = getMapVal( lineDataMap , 'WORK_ID' );
var _OBJECT_ID = getMapVal( lineDataMap , 'OBJECT_ID' );
//ひとまず全ACTIVE_FLGを1にセット
var sql = "" +
"UPDATE WFS_T_WORKFLOW SET ACTIVE_FLG = '1' " +
"WHERE WORK_ID = '" + _WORK_ID + "' " +
" AND OBJECT_ID = '" + _OBJECT_ID + "' ";
TalonDbUtil.update( TALON.getDbConfig(), sql );
var sql = "" +
"SELECT WORK_ID , OBJECT_ID , STEP , STATUS , LVL FROM WFS_T_WORKFLOW " +
"WHERE WORK_ID = '" + _WORK_ID + "' " +
" AND OBJECT_ID = '" + _OBJECT_ID + "' " +
"ORDER BY STEP ";
var itemSelectListSub = TalonDbUtil.select( TALON.getDbConfig(), sql );
for (var ii = 0; ii < itemSelectListSub.length; ii++) {
var lineDataMap = itemSelectListSub[ii];
// * var _STEP = lineDataMap['STEP'];
// * var _STATUS = lineDataMap['STATUS'];
// * var _LVL = lineDataMap['LVL'];
var _STEP = getMapVal( lineDataMap , 'STEP' );
var _STATUS = getMapVal( lineDataMap , 'STATUS' );
var _LVL = getMapVal( lineDataMap , 'LVL' );
//自分より下のSTEPで、自分のLVL以上のデータはACTIVE_FLGを0
var sql = "" +
"UPDATE WFS_T_WORKFLOW SET ACTIVE_FLG = '0' " +
"WHERE WORK_ID = '" + _WORK_ID + "' " +
" AND OBJECT_ID = '" + _OBJECT_ID + "' " +
" AND STEP < " + _STEP + " " +
" AND LVL >= " + _LVL + " ";
TalonDbUtil.update( TALON.getDbConfig(), sql );
}
}
// WFS_M_CONTROL の CATEGORY_ID (nullのデータについて99を更新)
//
//-------
TalonDbUtil.update( TALON.getDbConfig(), "UPDATE WFS_M_CONTROL SET CATEGORY_ID = '99' WHERE CATEGORY_ID IS NULL ");
TalonDbUtil.update( TALON.getDbConfig(), "UPDATE WFS_M_CONTROL SET APPROVAL_FLG = '0' WHERE APPROVAL_FLG IS NULL ");
TalonDbUtil.update( TALON.getDbConfig(), "UPDATE WFS_M_CONTROL SET ROUTE_SET_KBN = '0' WHERE ROUTE_SET_KBN IS NULL ");
}
//--------------------------------------------
// Ver1.7へのバージョンアップ
//--------------------------------------------
function exec_ver_up_17( _func_chk ){
//テーブルの追加
exec_ver_up_17_TableModify();
//データのパッチ(補填)
exec_ver_up_patch_17_DataPatch();
}
function exec_ver_up_17_TableModify(){
//テーブル変更、追加処理
//------------------------------
if ( TALON.getDbConfig().isOra() ) {
//--------------------------------------
//[新規]WFS_W_WORKFLOW
if (!table_exists('WFS_W_WORKFLOW')) {
executeSQL(
" CREATE TABLE WFS_W_WORKFLOW " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR2(100) NOT NULL," + "\n" +
" WORK_ID VARCHAR2(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR2(100) NOT NULL," + "\n" +
" STEP NUMBER(10,0) NOT NULL," + "\n" +
" OBJECT_NM VARCHAR2(500)," + "\n" +
" ROUTE_ID VARCHAR2(100)," + "\n" +
" USR_ID VARCHAR2(100)," + "\n" +
" STATUS VARCHAR2(20)," + "\n" +
" LVL NUMBER(10,0)," + "\n" +
" APP_MEMO VARCHAR2(4000)," + "\n" +
" RES_MEMO VARCHAR2(4000)," + "\n" +
" REJECT_KBN VARCHAR2(20)," + "\n" +
" CURENT_FLG VARCHAR2(20)," + "\n" +
" CREATED_DATE DATE," + "\n" +
" CREATED_BY VARCHAR2(50)," + "\n" +
" CREATED_PRG_NM VARCHAR2(50)," + "\n" +
" UPDATED_DATE DATE," + "\n" +
" UPDATED_BY VARCHAR2(50)," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50)," + "\n" +
" MODIFY_COUNT NUMBER(10,0)," + "\n" +
" SHONIN_ID VARCHAR2(100)," + "\n" +
" ACTIVE_FLG VARCHAR2(20)," + "\n" +
" HOLD_FLG VARCHAR2(20) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKFLOW " + "\n" +
" ADD(CONSTRAINT PK_WFS_W_WORKFLOW PRIMARY KEY (JOB_ID) USING INDEX)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_WORKAPPROVALRES
if (!table_exists('WFS_W_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR2(100) NOT NULL," + "\n" +
" WORK_ID VARCHAR2(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR2(100) NOT NULL," + "\n" +
" LVL DECIMAL(10,0) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR2(100) ," + "\n" +
" USR_GRP_ID VARCHAR2(100) ," + "\n" +
" USR_ID VARCHAR2(100) NOT NULL," + "\n" +
" CREATED_DATE DATE ," + "\n" +
" CREATED_BY VARCHAR2(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR2(50) ," + "\n" +
" UPDATED_DATE DATE ," + "\n" +
" UPDATED_BY VARCHAR2(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR2(50) ," + "\n" +
" MODIFY_COUNT NUMBER(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" ADD ( CONSTRAINT PK_WFS_W_WORKAPPROVALRES PRIMARY KEY (JOB_ID, WORK_ID, OBJECT_ID, LVL, USR_ID) USING INDEX ) " + "\n" +
"");
}
}
if ( TALON.getDbConfig().isMy() ) {
//--------------------------------------
//[新規]WFS_W_WORKFLOW
if (!table_exists('WFS_W_WORKFLOW ')) {
executeSQL(
" CREATE TABLE WFS_W_WORKFLOW " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR(100) NOT NULL," + "\n" +
" WORK_ID VARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR(100) NOT NULL," + "\n" +
" STEP DECIMAL(10,0) NOT NULL," + "\n" +
" OBJECT_NM VARCHAR(500)," + "\n" +
" ROUTE_ID VARCHAR(100)," + "\n" +
" USR_ID VARCHAR(100)," + "\n" +
" STATUS VARCHAR(20)," + "\n" +
" LVL DECIMAL(10,0)," + "\n" +
" APP_MEMO TEXT," + "\n" +
" RES_MEMO TEXT," + "\n" +
" REJECT_KBN VARCHAR(20)," + "\n" +
" CURENT_FLG VARCHAR(20)," + "\n" +
" CREATED_DATE DATETIME," + "\n" +
" CREATED_BY VARCHAR(50)," + "\n" +
" CREATED_PRG_NM VARCHAR(50)," + "\n" +
" UPDATED_DATE DATETIME," + "\n" +
" UPDATED_BY VARCHAR(50)," + "\n" +
" UPDATED_PRG_NM VARCHAR(50)," + "\n" +
" MODIFY_COUNT BIGINT(10)," + "\n" +
" SHONIN_ID VARCHAR(100)," + "\n" +
" ACTIVE_FLG VARCHAR(20)," + "\n" +
" HOLD_FLG VARCHAR(20) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKFLOW " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (JOB_ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_WORKAPPROVALRES
if (!table_exists('WFS_W_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" JOB_ID VARCHAR(100) NOT NULL," + "\n" +
" WORK_ID VARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID VARCHAR(100) NOT NULL," + "\n" +
" LVL DECIMAL(10,0) NOT NULL," + "\n" +
" ROUTE_ID VARCHAR(100) ," + "\n" +
" USR_GRP_ID VARCHAR(100) ," + "\n" +
" USR_ID VARCHAR(100) NOT NULL," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY VARCHAR(50) ," + "\n" +
" CREATED_PRG_NM VARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY VARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM VARCHAR(50) ," + "\n" +
" MODIFY_COUNT BIGINT(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PRIMARY KEY (JOB_ID, WORK_ID, OBJECT_ID, LVL, USR_ID)" + "\n" +
"");
}
};
if ( TALON.getDbConfig().isMssql() ) {
//--------------------------------------
//[新規]WFS_W_WORKFLOW
if (!table_exists('WFS_W_WORKFLOW ')) {
executeSQL(
" CREATE TABLE WFS_W_WORKFLOW " + "\n" +
" (" + "\n" +
" JOB_ID NVARCHAR(100) NOT NULL," + "\n" +
" WORK_ID NVARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID NVARCHAR(100) NOT NULL," + "\n" +
" STEP NUMERIC(10,0) NOT NULL," + "\n" +
" OBJECT_NM NVARCHAR(500) NULL," + "\n" +
" ROUTE_ID NVARCHAR(100) NULL," + "\n" +
" USR_ID NVARCHAR(100) NULL," + "\n" +
" STATUS NVARCHAR(20) NULL," + "\n" +
" LVL NUMERIC(10,0) NULL," + "\n" +
" APP_MEMO NVARCHAR(4000) NULL," + "\n" +
" RES_MEMO NVARCHAR(4000) NULL," + "\n" +
" REJECT_KBN NVARCHAR(20) NULL," + "\n" +
" CURENT_FLG NVARCHAR(20) NULL," + "\n" +
" CREATED_DATE DATETIME NULL," + "\n" +
" CREATED_BY NVARCHAR(50) NULL," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) NULL," + "\n" +
" UPDATED_DATE DATETIME NULL," + "\n" +
" UPDATED_BY NVARCHAR(50) NULL," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) NULL," + "\n" +
" MODIFY_COUNT NUMERIC(10,0) NULL," + "\n" +
" SHONIN_ID NVARCHAR(100)," + "\n" +
" ACTIVE_FLG NVARCHAR(20)," + "\n" +
" HOLD_FLG NVARCHAR(20) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKFLOW " + "\n" +
" ADD CONSTRAINT PK_WFS_W_WORKFLOW PRIMARY KEY NONCLUSTERED (JOB_ID)" + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_WORKAPPROVALRES
if (!table_exists('WFS_W_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" JOB_ID NVARCHAR(100) NOT NULL," + "\n" +
" WORK_ID NVARCHAR(100) NOT NULL," + "\n" +
" OBJECT_ID NVARCHAR(100) NOT NULL," + "\n" +
" LVL NUMERIC(10,0) NOT NULL," + "\n" +
" ROUTE_ID NVARCHAR(100) ," + "\n" +
" USR_GRP_ID NVARCHAR(100) ," + "\n" +
" USR_ID NVARCHAR(100) NOT NULL," + "\n" +
" CREATED_DATE DATETIME ," + "\n" +
" CREATED_BY NVARCHAR(50) ," + "\n" +
" CREATED_PRG_NM NVARCHAR(50) ," + "\n" +
" UPDATED_DATE DATETIME ," + "\n" +
" UPDATED_BY NVARCHAR(50) ," + "\n" +
" UPDATED_PRG_NM NVARCHAR(50) ," + "\n" +
" MODIFY_COUNT NUMERIC(10) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PK_WFS_W_WORKAPPROVALRES PRIMARY KEY NONCLUSTERED (JOB_ID, WORK_ID, OBJECT_ID, LVL, USR_ID) " + "\n" +
"");
}
};
if ( TALON.getDbConfig().isPostgres() ) {
//--------------------------------------
//[新規]WFS_W_WORKFLOW
if (!table_exists('WFS_W_WORKFLOW')) {
executeSQL(
" CREATE TABLE WFS_W_WORKFLOW " + "\n" +
" (" + "\n" +
" JOB_ID character varying(100) NOT NULL," + "\n" +
" WORK_ID character varying(100) NOT NULL," + "\n" +
" OBJECT_ID character varying(100) NOT NULL," + "\n" +
" STEP numeric(10,0) NOT NULL," + "\n" +
" OBJECT_NM character varying(500)," + "\n" +
" ROUTE_ID character varying(100)," + "\n" +
" USR_ID character varying(100)," + "\n" +
" STATUS character varying(20)," + "\n" +
" LVL numeric(10,0)," + "\n" +
" APP_MEMO character varying(4000)," + "\n" +
" RES_MEMO character varying(4000)," + "\n" +
" REJECT_KBN character varying(20)," + "\n" +
" CURENT_FLG character varying(20)," + "\n" +
" CREATED_DATE timestamp," + "\n" +
" CREATED_BY character varying(50)," + "\n" +
" CREATED_PRG_NM character varying(50)," + "\n" +
" UPDATED_DATE timestamp," + "\n" +
" UPDATED_BY character varying(50)," + "\n" +
" UPDATED_PRG_NM character varying(50)," + "\n" +
" MODIFY_COUNT numeric(10,0)," + "\n" +
" SHONIN_ID character varying(100)," + "\n" +
" ACTIVE_FLG character varying(20)," + "\n" +
" HOLD_FLG character varying(20) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKFLOW " + "\n" +
" ADD CONSTRAINT PK_WFS_W_WORKFLOW PRIMARY KEY (JOB_ID) " + "\n" +
"");
}
//--------------------------------------
//[新規]WFS_W_WORKAPPROVALRES
if (!table_exists('WFS_W_WORKAPPROVALRES')) {
executeSQL(
" CREATE TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" (" + "\n" +
" JOB_ID character varying(100) NOT NULL," + "\n" +
" WORK_ID character varying(100) NOT NULL," + "\n" +
" OBJECT_ID character varying(100) NOT NULL," + "\n" +
" LVL numeric(10,0) NOT NULL," + "\n" +
" ROUTE_ID character varying(100) ," + "\n" +
" USR_GRP_ID character varying(100) ," + "\n" +
" USR_ID character varying(100) NOT NULL," + "\n" +
" CREATED_DATE timestamp ," + "\n" +
" CREATED_BY character varying(50) ," + "\n" +
" CREATED_PRG_NM character varying(50) ," + "\n" +
" UPDATED_DATE timestamp ," + "\n" +
" UPDATED_BY character varying(50) ," + "\n" +
" UPDATED_PRG_NM character varying(50) ," + "\n" +
" MODIFY_COUNT numeric(10,0) " + "\n" +
" )" + "\n" +
"");
//--------------------
executeSQL(
" ALTER TABLE WFS_W_WORKAPPROVALRES " + "\n" +
" ADD CONSTRAINT PK_WFS_W_WORKAPPROVALRES PRIMARY KEY (JOB_ID, WORK_ID, OBJECT_ID, LVL, USR_ID) " + "\n" +
"");
}
};
}
function exec_ver_up_patch_17_DataPatch(){
}
function exec_create_Function() {
//≪FUNCTION DROP≫
//--------------------
//[FUNCTION]WFS_ALL_MAIL
function_exists_drop('WFS_ALL_MAIL');
//[FUNCTION]WFS_AUTH_SHINSEI
function_exists_drop('WFS_AUTH_SHINSEI');
//[FUNCTION]WFS_WF_EXISTS
function_exists_drop('WFS_WF_EXISTS');
//[FUNCTION]Ver14追加分 WFS_AUTH_MAIN
function_exists_drop('WFS_AUTH_MAIN');
//[FUNCTION]Ver14追加分 WFS_AUTH_SHONIN
function_exists_drop('WFS_AUTH_SHONIN');
//[FUNCTION]Ver14追加分 WFS_WF_STEP
function_exists_drop('WFS_WF_STEP');
if ( TALON.getDbConfig().isOra() ) {
//--------------------
//WFS_ALL_MAIL
executeSQL(
"CREATE FUNCTION WFS_ALL_MAIL( " + "\n" +
" P_USR_GRP_ID IN VARCHAR2 " + "\n" +
" ,P_USR_ID IN VARCHAR2 " + "\n" +
" ,P_WORK_ID IN VARCHAR2 " + "\n" +
" ,P_OBJECT_ID IN VARCHAR2 " + "\n" +
" ,P_LVL IN DECIMAL " + "\n" +
" ) " + "\n" +
"RETURN VARCHAR2 " + "\n" +
"AS " + "\n" +
" REC VARCHAR2(4000); " + "\n" +
" TMP VARCHAR2(100); " + "\n" +
"BEGIN " + "\n" +
" REC := NULL; " + "\n" +
" TMP := NULL; " + "\n" +
" " + "\n" +
" DECLARE " + "\n" +
" CURSOR CUR_MAIL IS " + "\n" +
" SELECT " + "\n" +
" WFS_M_USR_GRP_DEPDTL.MAIL as MAIL " + "\n" +
" FROM WFS_M_USR_GRP_DEPDTL " + "\n" +
" LEFT OUTER JOIN ( " + "\n" +
" SELECT " + "\n" +
" COUNT(*) AS CNT " + "\n" +
" FROM WFS_T_WORKAPPROVALRES " + "\n" +
" WHERE WORK_ID = P_WORK_ID " + "\n" +
" AND OBJECT_ID = P_OBJECT_ID " + "\n" +
" AND LVL = P_LVL " + "\n" +
" ) WFS_T_WORKAPPROVALRES_CNT " + "\n" +
" ON 1 = 1 " + "\n" +
" LEFT OUTER JOIN ( " + "\n" +
" SELECT " + "\n" +
" USR_ID " + "\n" +
" FROM WFS_T_WORKAPPROVALRES " + "\n" +
" WHERE WORK_ID = P_WORK_ID " + "\n" +
" AND OBJECT_ID = P_OBJECT_ID " + "\n" +
" AND LVL = P_LVL " + "\n" +
" ) WFS_T_WORKAPPROVALRES " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_T_WORKAPPROVALRES.USR_ID " + "\n" +
" WHERE WFS_M_USR_GRP_DEPDTL.USR_GRP_ID = P_USR_GRP_ID " + "\n" +
" AND (WFS_M_USR_GRP_DEPDTL.USR_ID = P_USR_ID OR P_USR_ID IS NULL) " + "\n" +
" AND ( " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NULL " + "\n" +
" OR " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT = 0 " + "\n" +
" OR " + "\n" +
" ( " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NOT NULL " + "\n" +
" AND " + "\n" +
" WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_T_WORKAPPROVALRES.USR_ID " + "\n" +
" ) " + "\n" +
" ); " + "\n" +
" BEGIN " + "\n" +
" FOR RCD IN CUR_MAIL LOOP " + "\n" +
" IF (RCD.MAIL IS NOT NULL) THEN " + "\n" +
" IF (REC IS NULL) THEN " + "\n" +
" REC := RCD.MAIL; " + "\n" +
" ELSE " + "\n" +
" REC := REC || ',' || RCD.MAIL; " + "\n" +
" END IF; " + "\n" +
" END IF; " + "\n" +
" END LOOP; " + "\n" +
" END; " + "\n" +
" " + "\n" +
" RETURN REC; " + "\n" +
" " + "\n" +
"END WFS_ALL_MAIL; " + "\n" +
""
);
//--------------------
//WFS_AUTH_MAIN
executeSQL(
"CREATE FUNCTION WFS_AUTH_MAIN( " + "\n" +
" P_WORK_ID IN VARCHAR " + "\n" +
" ,P_ROUTE_ID IN VARCHAR " + "\n" +
" ,P_USR_ID IN VARCHAR " + "\n" +
" ,P_LVL IN DECIMAL " + "\n" +
" ,P_KBN IN VARCHAR " + "\n" +
" ) " + "\n" +
"RETURN VARCHAR2 " + "\n" +
"AS " + "\n" +
" -- P_KBN 1:申請 2:承認 " + "\n" +
" REC VARCHAR2(20); " + "\n" +
"BEGIN " + "\n" +
" REC := NULL; " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" CASE " + "\n" +
" WHEN COUNT(*) = 0 THEN '0' " + "\n" +
" ELSE '1' " + "\n" +
" END STATUS INTO REC " + "\n" +
" FROM ( " + "\n" +
" SELECT " + "\n" +
" WFS_M_AUTH.WORK_ID " + "\n" +
" ,WFS_M_AUTH.ROUTE_ID " + "\n" +
" ,WFS_M_AUTH.LVL " + "\n" +
" ,WFS_M_USR_GRP_DEPDTL.USR_ID " + "\n" +
" ,'0' AS KBN " + "\n" +
" ,'' AS SEIKI_USR_ID " + "\n" +
" FROM WFS_M_AUTH " + "\n" +
" INNER JOIN WFS_M_USR_GRP_DEPDTL " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_GRP_ID = WFS_M_AUTH.USR_GRP_ID " + "\n" +
" " + "\n" +
" UNION ALL " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" WFS_M_AUTH.WORK_ID " + "\n" +
" ,WFS_M_AUTH.ROUTE_ID " + "\n" +
" ,WFS_M_AUTH.LVL " + "\n" +
" ,WFS_M_USR_DAIRI.DAIRI_USR_ID AS USR_ID " + "\n" +
" ,'1' AS KBN " + "\n" +
" ,WFS_M_USR_DAIRI.USR_ID AS SEIKI_USR_ID " + "\n" +
" FROM WFS_M_AUTH " + "\n" +
" INNER JOIN WFS_M_USR_GRP_DEPDTL " + "\n" +
" ON WFS_M_AUTH.USR_GRP_ID = WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " + "\n" +
" INNER JOIN WFS_M_USR_DAIRI " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_M_USR_DAIRI.USR_ID " + "\n" +
" AND WFS_M_USR_DAIRI.YUKO_KBN = '1' " + "\n" +
" AND WFS_M_USR_DAIRI.SHINSEI_FLG = CASE WHEN P_KBN = '1' THEN '1' ELSE '0' END " + "\n" +
" AND WFS_M_USR_DAIRI.SHONIN_FLG = CASE WHEN P_KBN = '2' THEN '1' ELSE '0' END " + "\n" +
" ) MN " + "\n" +
" WHERE MN.WORK_ID = P_WORK_ID " + "\n" +
" AND MN.ROUTE_ID = P_ROUTE_ID " + "\n" +
" AND MN.LVL = P_LVL " + "\n" +
" AND MN.USR_ID = P_USR_ID " + "\n" +
" ; " + "\n" +
" " + "\n" +
" RETURN REC; " + "\n" +
" " + "\n" +
" END WFS_AUTH_MAIN; " + "\n" +
""
);
//--------------------
//WFS_AUTH_SHINSEI
executeSQL(
"CREATE FUNCTION WFS_AUTH_SHINSEI ( " + "\n" +
" P_WORK_ID VARCHAR2 " + "\n" +
" ,P_ROUTE_ID VARCHAR2 " + "\n" +
" ,P_USR_ID VARCHAR2 " + "\n" +
") " + "\n" +
"RETURN VARCHAR2 " + "\n" +
"AS " + "\n" +
" REC VARCHAR2(20); " + "\n" +
"BEGIN " + "\n" +
" REC := WFS_AUTH_MAIN(P_WORK_ID,P_ROUTE_ID,P_USR_ID,1,'1'); " + "\n" +
" RETURN REC; " + "\n" +
"END WFS_AUTH_SHINSEI; " + "\n" +
""
);
//--------------------
//WFS_AUTH_SHINSEI
executeSQL(
"CREATE FUNCTION WFS_AUTH_SHONIN ( " + "\n" +
" P_WORK_ID VARCHAR2 " + "\n" +
" ,P_ROUTE_ID VARCHAR2 " + "\n" +
" ,P_USR_ID VARCHAR2 " + "\n" +
" ,P_LVL DECIMAL " + "\n" +
") " + "\n" +
"RETURN VARCHAR2 " + "\n" +
"AS " + "\n" +
" REC VARCHAR2(20); " + "\n" +
"BEGIN " + "\n" +
" REC := WFS_AUTH_MAIN(P_WORK_ID,P_ROUTE_ID,P_USR_ID,P_LVL,'2'); " + "\n" +
" RETURN REC; " + "\n" +
"END WFS_AUTH_SHONIN; " + "\n" +
""
);
//--------------------
//WFS_WF_EXISTS
executeSQL(
"CREATE FUNCTION WFS_WF_EXISTS( " + "\n" +
" P_WORK_ID VARCHAR2 " + "\n" +
" ,P_OBJECT_ID VARCHAR2 " + "\n" +
") " + "\n" +
"RETURN VARCHAR2 " + "\n" +
"AS " + "\n" +
" REC VARCHAR2(20); " + "\n" +
"BEGIN " + "\n" +
" REC := NULL; " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" CASE " + "\n" +
" WHEN COUNT(*) = 0 THEN '0' " + "\n" +
" ELSE '1' " + "\n" +
" END STATUS INTO REC " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" WHERE WORK_ID = P_WORK_ID " + "\n" +
" AND OBJECT_ID = P_OBJECT_ID " + "\n" +
" ; " + "\n" +
" " + "\n" +
" IF (REC = '1') THEN " + "\n" +
" SELECT " + "\n" +
" CASE " + "\n" +
" WHEN WFS_T_WORKFLOW.LVL = 1 AND STATUS <> '6' THEN '1' " + "\n" +
" WHEN WFS_T_WORKFLOW.LVL = 1 AND STATUS = '6' THEN '4' " + "\n" +
" WHEN WFS_LEVEL.LVL = WFS_T_WORKFLOW.LVL AND WFS_T_WORKFLOW.STATUS = '2' THEN '3' " + "\n" +
" WHEN WFS_T_WORKFLOW.STATUS = '9' THEN '9' " + "\n" +
" ELSE '2' " + "\n" +
" END STATUS INTO REC " + "\n" +
" FROM ( " + "\n" +
" SELECT " + "\n" +
" S1.WORK_ID " + "\n" +
" ,S1.OBJECT_ID " + "\n" +
" ,S1.STEP " + "\n" +
" ,S1.LVL " + "\n" +
" ,S1.STATUS " + "\n" +
" ,S1.ROUTE_ID " + "\n" +
" FROM WFS_T_WORKFLOW S1 " + "\n" +
" INNER JOIN ( " + "\n" +
" SELECT " + "\n" +
" WORK_ID " + "\n" +
" ,OBJECT_ID " + "\n" +
" ,MAX(STEP) AS STEP " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" GROUP BY " + "\n" +
" WORK_ID " + "\n" +
" ,OBJECT_ID " + "\n" +
" ) S2 " + "\n" +
" ON S2.WORK_ID = S1.WORK_ID " + "\n" +
" AND S2.OBJECT_ID = S1.OBJECT_ID " + "\n" +
" AND S2.STEP = S1.STEP " + "\n" +
" ) WFS_T_WORKFLOW " + "\n" +
" LEFT OUTER JOIN WFS_M_CONTROL " + "\n" +
" ON WFS_M_CONTROL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " + "\n" +
" LEFT OUTER JOIN ( SELECT WORK_ID, ROUTE_ID, MAX(LVL) AS LVL FROM WFS_M_AUTH GROUP BY WORK_ID, ROUTE_ID ) WFS_LEVEL " + "\n" +
" ON WFS_LEVEL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " + "\n" +
" AND WFS_LEVEL.ROUTE_ID = WFS_T_WORKFLOW.ROUTE_ID " + "\n" +
" WHERE WFS_T_WORKFLOW.WORK_ID = P_WORK_ID " + "\n" +
" AND WFS_T_WORKFLOW.OBJECT_ID = P_OBJECT_ID " + "\n" +
" ; " + "\n" +
" END IF; " + "\n" +
" " + "\n" +
" RETURN REC; " + "\n" +
" " + "\n" +
"END WFS_WF_EXISTS; " + "\n" +
""
);
//--------------------
//WFS_WF_STEP
executeSQL(
"CREATE FUNCTION WFS_WF_STEP ( " + "\n" +
" P_WORK_ID VARCHAR2 " + "\n" +
" ,P_OBJECT_ID VARCHAR2 " + "\n" +
" ) " + "\n" +
"RETURN DECIMAL " + "\n" +
"AS " + "\n" +
" REC DECIMAL(10,0); " + "\n" +
"BEGIN " + "\n" +
" REC := 0; " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" MAX(STEP) AS STEP " + "\n" +
" INTO REC " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" WHERE WORK_ID = P_WORK_ID " + "\n" +
" AND OBJECT_ID = P_OBJECT_ID " + "\n" +
" ; " + "\n" +
" " + "\n" +
" RETURN REC; " + "\n" +
" " + "\n" +
"END WFS_WF_STEP; " + "\n" +
""
);
};
if ( TALON.getDbConfig().isMy() ) {
//SQLファイルで作成
};
if ( TALON.getDbConfig().isMssql() ) {
//--------------------
//WFS_ALL_MAIL
executeSQL(
" CREATE FUNCTION [dbo].[WFS_ALL_MAIL]( " + "\n" +
" @P_USR_GRP_ID VARCHAR(100) " + "\n" +
" ,@P_USR_ID VARCHAR(100) " + "\n" +
" ,@P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_OBJECT_ID VARCHAR(100) " + "\n" +
" ,@P_LVL DECIMAL(10,0) " + "\n" +
" ) RETURNS VARCHAR(4000) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @TMP VARCHAR(100) " + "\n" +
" DECLARE @REC VARCHAR(4000) " + "\n" +
" " + "\n" +
" SET @REC = NULL " + "\n" +
" " + "\n" +
" " + "\n" +
" DECLARE CUR_MAIL CURSOR FOR " + "\n" +
" SELECT " + "\n" +
" WFS_M_USR_GRP_DEPDTL.MAIL as MAIL " + "\n" +
" FROM WFS_M_USR_GRP_DEPDTL " + "\n" +
" LEFT OUTER JOIN ( " + "\n" +
" SELECT " + "\n" +
" COUNT(*) AS CNT " + "\n" +
" FROM WFS_T_WORKAPPROVALRES " + "\n" +
" WHERE WORK_ID = @P_WORK_ID " + "\n" +
" AND OBJECT_ID = @P_OBJECT_ID " + "\n" +
" AND LVL = @P_LVL " + "\n" +
" ) WFS_T_WORKAPPROVALRES_CNT " + "\n" +
" ON 1 = 1 " + "\n" +
" LEFT OUTER JOIN ( " + "\n" +
" SELECT " + "\n" +
" USR_ID " + "\n" +
" FROM WFS_T_WORKAPPROVALRES " + "\n" +
" WHERE WORK_ID = @P_WORK_ID " + "\n" +
" AND OBJECT_ID = @P_OBJECT_ID " + "\n" +
" AND LVL = @P_LVL " + "\n" +
" ) WFS_T_WORKAPPROVALRES " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_T_WORKAPPROVALRES.USR_ID " + "\n" +
" WHERE WFS_M_USR_GRP_DEPDTL.USR_GRP_ID = @P_USR_GRP_ID " + "\n" +
" AND (WFS_M_USR_GRP_DEPDTL.USR_ID = @P_USR_ID OR @P_USR_ID IS NULL) " + "\n" +
" AND ( " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NULL " + "\n" +
" OR " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT = 0 " + "\n" +
" OR " + "\n" +
" ( " + "\n" +
" WFS_T_WORKAPPROVALRES_CNT.CNT IS NOT NULL " + "\n" +
" AND " + "\n" +
" WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_T_WORKAPPROVALRES.USR_ID " + "\n" +
" ) " + "\n" +
" ) " + "\n" +
" " + "\n" +
" OPEN CUR_MAIL " + "\n" +
" " + "\n" +
" FETCH NEXT FROM CUR_MAIL INTO @TMP " + "\n" +
" " + "\n" +
" WHILE @@FETCH_STATUS = 0 " + "\n" +
" BEGIN " + "\n" +
" IF (@TMP IS NOT NULL) " + "\n" +
" BEGIN " + "\n" +
" IF (@REC IS NOT NULL) " + "\n" +
" BEGIN " + "\n" +
" SET @REC = @REC + ',' + @TMP " + "\n" +
" END " + "\n" +
" IF (@REC IS NULL) " + "\n" +
" BEGIN " + "\n" +
" SET @REC = @TMP " + "\n" +
" END " + "\n" +
" END " + "\n" +
" FETCH NEXT FROM CUR_MAIL INTO @TMP " + "\n" +
" END " + "\n" +
" CLOSE CUR_MAIL " + "\n" +
" DEALLOCATE CUR_MAIL " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
//--------------------
//WFS_AUTH_MAIN
executeSQL(
" CREATE FUNCTION [dbo].[WFS_AUTH_MAIN]( " + "\n" +
" @P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_ROUTE_ID VARCHAR(100) " + "\n" +
" ,@P_USR_ID VARCHAR(100) " + "\n" +
" ,@P_LVL DECIMAL(10,0) " + "\n" +
" ,@P_KBN VARCHAR(10) " + "\n" +
" ) RETURNS VARCHAR(100) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @TMP VARCHAR(100) " + "\n" +
" DECLARE @REC VARCHAR(20) " + "\n" +
" " + "\n" +
" SET @REC = NULL " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" @REC = " + "\n" +
" CASE " + "\n" +
" WHEN COUNT(*) = 0 THEN '0' " + "\n" +
" ELSE '1' " + "\n" +
" END " + "\n" +
" FROM ( " + "\n" +
" SELECT " + "\n" +
" WFS_M_AUTH.WORK_ID " + "\n" +
" ,WFS_M_AUTH.ROUTE_ID " + "\n" +
" ,WFS_M_AUTH.LVL " + "\n" +
" ,WFS_M_USR_GRP_DEPDTL.USR_ID " + "\n" +
" ,'0' AS KBN " + "\n" +
" ,'' AS SEIKI_USR_ID " + "\n" +
" FROM WFS_M_AUTH " + "\n" +
" INNER JOIN WFS_M_USR_GRP_DEPDTL " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_GRP_ID = WFS_M_AUTH.USR_GRP_ID " + "\n" +
" " + "\n" +
" UNION ALL " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" WFS_M_AUTH.WORK_ID " + "\n" +
" ,WFS_M_AUTH.ROUTE_ID " + "\n" +
" ,WFS_M_AUTH.LVL " + "\n" +
" ,WFS_M_USR_DAIRI.DAIRI_USR_ID AS USR_ID " + "\n" +
" ,'1' AS KBN " + "\n" +
" ,WFS_M_USR_DAIRI.USR_ID AS SEIKI_USR_ID " + "\n" +
" FROM WFS_M_AUTH " + "\n" +
" INNER JOIN WFS_M_USR_GRP_DEPDTL " + "\n" +
" ON WFS_M_AUTH.USR_GRP_ID = WFS_M_USR_GRP_DEPDTL.USR_GRP_ID " + "\n" +
" INNER JOIN WFS_M_USR_DAIRI " + "\n" +
" ON WFS_M_USR_GRP_DEPDTL.USR_ID = WFS_M_USR_DAIRI.USR_ID " + "\n" +
" AND WFS_M_USR_DAIRI.YUKO_KBN = '1' " + "\n" +
" AND WFS_M_USR_DAIRI.SHINSEI_FLG = CASE WHEN @P_KBN = '1' THEN '1' ELSE '0' END " + "\n" +
" AND WFS_M_USR_DAIRI.SHONIN_FLG = CASE WHEN @P_KBN = '2' THEN '1' ELSE '0' END " + "\n" +
" ) MN " + "\n" +
" WHERE MN.WORK_ID = @P_WORK_ID " + "\n" +
" AND MN.ROUTE_ID = @P_ROUTE_ID " + "\n" +
" AND MN.LVL = @P_LVL " + "\n" +
" AND MN.USR_ID = @P_USR_ID " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
//--------------------
//WFS_AUTH_SHINSEI
executeSQL(
" CREATE FUNCTION [dbo].[WFS_AUTH_SHINSEI]( " + "\n" +
" @P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_ROUTE_ID VARCHAR(100) " + "\n" +
" ,@P_USR_ID VARCHAR(100) " + "\n" +
" ) RETURNS VARCHAR(100) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @REC VARCHAR(20) " + "\n" +
" " + "\n" +
" SET @REC = [dbo].[WFS_AUTH_MAIN](@P_WORK_ID,@P_ROUTE_ID,@P_USR_ID,1,'1') " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
//--------------------
//WFS_AUTH_SHINSEI
executeSQL(
" CREATE FUNCTION [dbo].[WFS_AUTH_SHONIN]( " + "\n" +
" @P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_ROUTE_ID VARCHAR(100) " + "\n" +
" ,@P_USR_ID VARCHAR(100) " + "\n" +
" ,@P_LVL DECIMAL(10,0) " + "\n" +
" ) RETURNS VARCHAR(100) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @REC VARCHAR(20) " + "\n" +
" " + "\n" +
" SET @REC = [dbo].[WFS_AUTH_MAIN](@P_WORK_ID,@P_ROUTE_ID,@P_USR_ID,@P_LVL,'2') " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
//--------------------
//WFS_WF_EXISTS
executeSQL(
" CREATE FUNCTION [dbo].[WFS_WF_EXISTS]( " + "\n" +
" @P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_OBJECT_ID VARCHAR(100) " + "\n" +
" ) RETURNS VARCHAR(100) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @TMP VARCHAR(100) " + "\n" +
" DECLARE @REC VARCHAR(20) " + "\n" +
" " + "\n" +
" SET @REC = NULL " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" @REC = " + "\n" +
" CASE " + "\n" +
" WHEN COUNT(*) = 0 THEN '0' " + "\n" +
" ELSE '1' " + "\n" +
" END " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" WHERE WORK_ID = @P_WORK_ID " + "\n" +
" AND OBJECT_ID = @P_OBJECT_ID " + "\n" +
" " + "\n" +
" " + "\n" +
" IF (@REC = '1') " + "\n" +
" BEGIN " + "\n" +
" SELECT " + "\n" +
" @REC = " + "\n" +
" CASE " + "\n" +
" WHEN WFS_T_WORKFLOW.LVL = 1 AND STATUS <> '6' THEN '1' " + "\n" +
" WHEN WFS_T_WORKFLOW.LVL = 1 AND STATUS = '6' THEN '4' " + "\n" +
" WHEN WFS_LEVEL.LVL = WFS_T_WORKFLOW.LVL AND WFS_T_WORKFLOW.STATUS = '2' THEN '3' " + "\n" +
" WHEN WFS_T_WORKFLOW.STATUS = '9' THEN '9' " + "\n" +
" ELSE '2' " + "\n" +
" END " + "\n" +
" FROM ( " + "\n" +
" SELECT " + "\n" +
" S1.WORK_ID " + "\n" +
" ,S1.OBJECT_ID " + "\n" +
" ,S1.STEP " + "\n" +
" ,S1.LVL " + "\n" +
" ,S1.STATUS " + "\n" +
" ,S1.ROUTE_ID " + "\n" +
" FROM WFS_T_WORKFLOW S1 " + "\n" +
" INNER JOIN ( " + "\n" +
" SELECT " + "\n" +
" WORK_ID " + "\n" +
" ,OBJECT_ID " + "\n" +
" ,MAX(STEP) AS STEP " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" GROUP BY " + "\n" +
" WORK_ID " + "\n" +
" ,OBJECT_ID " + "\n" +
" ) S2 " + "\n" +
" ON S2.WORK_ID = S1.WORK_ID " + "\n" +
" AND S2.OBJECT_ID = S1.OBJECT_ID " + "\n" +
" AND S2.STEP = S1.STEP " + "\n" +
" ) WFS_T_WORKFLOW " + "\n" +
" LEFT OUTER JOIN WFS_M_CONTROL " + "\n" +
" ON WFS_M_CONTROL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " + "\n" +
" LEFT OUTER JOIN ( SELECT WORK_ID, ROUTE_ID, MAX(LVL) AS LVL FROM WFS_M_AUTH GROUP BY WORK_ID, ROUTE_ID ) WFS_LEVEL " + "\n" +
" ON WFS_LEVEL.WORK_ID = WFS_T_WORKFLOW.WORK_ID " + "\n" +
" AND WFS_LEVEL.ROUTE_ID = WFS_T_WORKFLOW.ROUTE_ID " + "\n" +
" WHERE WFS_T_WORKFLOW.WORK_ID = @P_WORK_ID " + "\n" +
" AND WFS_T_WORKFLOW.OBJECT_ID = @P_OBJECT_ID " + "\n" +
" " + "\n" +
" END " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
//--------------------
//WFS_WF_STEP
executeSQL(
" CREATE FUNCTION [dbo].[WFS_WF_STEP]( " + "\n" +
" @P_WORK_ID VARCHAR(100) " + "\n" +
" ,@P_OBJECT_ID VARCHAR(100) " + "\n" +
" ) RETURNS decimal(10,0) AS " + "\n" +
" BEGIN " + "\n" +
" DECLARE @REC DECIMAL(10,0) " + "\n" +
" " + "\n" +
" SET @REC = 0 " + "\n" +
" " + "\n" +
" SELECT " + "\n" +
" @REC = " + "\n" +
" MAX(STEP) " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" WHERE WORK_ID = @P_WORK_ID " + "\n" +
" AND OBJECT_ID = @P_OBJECT_ID " + "\n" +
" " + "\n" +
" RETURN @REC " + "\n" +
" END " + "\n" +
""
);
};
if ( TALON.getDbConfig().isPostgres() ) {
//SQLファイルで作成
};
}
function exec_create_View() {
//≪VIEW DROP≫
//--------------------
//[VIEW]Ver14追加分 WFS_WF_STATUS_LIST
view_exists_drop('WFS_WF_STATUS_LIST');
//[VIEW]Ver14追加分 WFS_WF_STATUS_LIST_SUB
view_exists_drop('WFS_WF_STATUS_LIST_SUB');
if ( TALON.getDbConfig().isOra() ) {
//--------------------
//WFS_WF_STATUS_LIST_SUB
executeSQL(
"CREATE VIEW WFS_WF_STATUS_LIST_SUB AS " + "\n" +
" SELECT " + "\n" +
" WFS_T_WORKFLOW.WORK_ID AS WORK_ID, " + "\n" +
" WFS_T_WORKFLOW.OBJECT_ID AS OBJECT_ID, " + "\n" +
" WFS_T_WORKFLOW.LVL AS LVL, " + "\n" +
" MAX(WFS_T_WORKFLOW.STEP) AS STEP " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" GROUP BY WFS_T_WORKFLOW.WORK_ID , WFS_T_WORKFLOW.OBJECT_ID , WFS_T_WORKFLOW.LVL " + "\n" +
""
);
//--------------------
//WFS_WF_STATUS_LIST_SUB
executeSQL(
"CREATE VIEW WFS_WF_STATUS_LIST AS " + "\n" +
" SELECT " + "\n" +
" MN.WORK_ID " + "\n" +
" ,MN.OBJECT_ID " + "\n" +
" ,MN.LVL " + "\n" +
" ,MN.STEP " + "\n" +
" ,MN.STATUS " + "\n" +
" ,MN.CREATED_BY " + "\n" +
" ,MN.CREATED_DATE " + "\n" +
" ,MN.UPDATED_BY AS WFS_ID " + "\n" +
" ,TLN_M_USER.USER_NM AS WFS_NAME " + "\n" +
" ,MN.UPDATED_DATE AS WFS_DATE " + "\n" +
" FROM WFS_T_WORKFLOW MN " + "\n" +
" INNER JOIN WFS_WF_STATUS_LIST_SUB MX " + "\n" +
" ON MX.WORK_ID = MN.WORK_ID " + "\n" +
" AND MX.OBJECT_ID = MN.OBJECT_ID " + "\n" +
" AND MX.LVL = MN.LVL " + "\n" +
" AND MX.STEP = MN.STEP " + "\n" +
" AND MN.STATUS IN ('1','2') " + "\n" +
" AND MN.ACTIVE_FLG = '1' " + "\n" +
" LEFT OUTER JOIN TLN_M_USER " + "\n" +
" ON MN.UPDATED_BY = TLN_M_USER.USER_ID " + "\n" +
""
);
};
if ( TALON.getDbConfig().isMy() ) {
//SQLファイルで作成
};
if ( TALON.getDbConfig().isMssql() ) {
//--------------------
//WFS_WF_STATUS_LIST_SUB
executeSQL(
"CREATE VIEW WFS_WF_STATUS_LIST_SUB AS " + "\n" +
" SELECT " + "\n" +
" WFS_T_WORKFLOW.WORK_ID AS WORK_ID, " + "\n" +
" WFS_T_WORKFLOW.OBJECT_ID AS OBJECT_ID, " + "\n" +
" WFS_T_WORKFLOW.LVL AS LVL, " + "\n" +
" MAX(WFS_T_WORKFLOW.STEP) AS STEP " + "\n" +
" FROM WFS_T_WORKFLOW " + "\n" +
" GROUP BY WFS_T_WORKFLOW.WORK_ID , WFS_T_WORKFLOW.OBJECT_ID , WFS_T_WORKFLOW.LVL " + "\n" +
""
);
//--------------------
//WFS_WF_STATUS_LIST_SUB
executeSQL(
"CREATE VIEW WFS_WF_STATUS_LIST AS " + "\n" +
" SELECT " + "\n" +
" MN.WORK_ID " + "\n" +
" ,MN.OBJECT_ID " + "\n" +
" ,MN.LVL " + "\n" +
" ,MN.STEP " + "\n" +
" ,MN.STATUS " + "\n" +
" ,MN.CREATED_BY " + "\n" +
" ,MN.CREATED_DATE " + "\n" +
" ,MN.UPDATED_BY AS WFS_ID " + "\n" +
" ,TLN_M_USER.USER_NM AS WFS_NAME " + "\n" +
" ,MN.UPDATED_DATE AS WFS_DATE " + "\n" +
" FROM WFS_T_WORKFLOW MN " + "\n" +
" INNER JOIN WFS_WF_STATUS_LIST_SUB MX " + "\n" +
" ON MX.WORK_ID = MN.WORK_ID " + "\n" +
" AND MX.OBJECT_ID = MN.OBJECT_ID " + "\n" +
" AND MX.LVL = MN.LVL " + "\n" +
" AND MX.STEP = MN.STEP " + "\n" +
" AND MN.STATUS IN ('1','2') " + "\n" +
" AND MN.ACTIVE_FLG = '1' " + "\n" +
" LEFT OUTER JOIN TLN_M_USER " + "\n" +
" ON MN.UPDATED_BY = TLN_M_USER.USER_ID " + "\n" +
""
);
};
if ( TALON.getDbConfig().isPostgres() ) {
//SQLファイルで作成
};
}
≣ サーバJS ライブラリXDMF_JS001_0 [共通]共通 56159字
//-------------------------------------------
//[部品]共通
//-------------------------------------------
var _USER_ID = '';
var _FUNC_ID = '';
function tln_com_escape(val) {
return val.replace("'","''");
}
//システム日付を返す
//更新時、データベースの日付型項目へバインドする際に使用(更新日付など)
function tln_com_nowdate() {
var sysDate = new java.util.Date();
return sysDate;
}
//システム日付(文字列 YYYY-MM-DD HH:MI:SS)を返す
//更新時、タイムスタンプ型としてSQLに組み込む際に使用
function tln_com_nowdate_str() {
var sysDate = new java.util.Date();
return (sysDate.getYear()+1900) + "-" + (sysDate.getMonth()+1) + "-" + sysDate.getDate() + " " + sysDate.getHours() + ":" + sysDate.getMinutes() + ":" + sysDate.getSeconds();
}
//文字列型の日付(画面項目)(YYYY/MM/DD)を日付型に変換
function tln_com_todate(val) {
y = parseInt(val.split("/")[0]) - 1900;
m = parseInt(val.split("/")[1]) - 1;
d = parseInt(val.split("/")[2]);
var sysDate = new java.util.Date(y,m,d);
return sysDate;
}
//文字列型の日付(YYYY-MM-DD HH:MI)を日付型に変換
function tln_com_todatetime(val) {
//val = val.replace("-","/")
var regExp = new RegExp( "-", "g" ) ;
val = val.replace( regExp , "/" ) ;
var val1 = val.split(" ")[0];
var val2 = val.split(" ")[1];
var y = parseInt(val1.split("/")[0]) - 1900;
var m = parseInt(val1.split("/")[1]) - 1;
var d = parseInt(val1.split("/")[2]) + 0;
var h = parseInt(val2.split(":")[0]);
var f = parseInt(val2.split(":")[1]);
var sysDate = new java.util.Date(y,m,d,h,f);
return sysDate;
}
//日付型を文字列型に変換(単純変換)
function tln_com_date2string(obj) {
if (obj == null) {
return null;
} else {
return obj.toString();
}
}
//日付型を文字列型に変換(YYYY-MM-DD HH:MI:SS変換)
//function tln_com_date2string2(obj) {
// return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + " " + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
//}
//日付型を文字列型に変換(YYYY-MM-DD HH:MI:SS変換)
function tln_com_date2string2(obj) {
var DTYPE = 'DATETIME';
try {
var tmp = obj.getHours();
} catch(e) {
DTYPE = 'DATE';
}
if ( DTYPE == 'DATETIME' ) {
return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + " " + tln_com_zpad2(obj.getHours()) + ":" + tln_com_zpad2(obj.getMinutes()) + ":" + tln_com_zpad2(obj.getSeconds());
} else {
return (obj.getYear()+1900) + "-" + tln_com_zpad2(obj.getMonth()+1) + "-" + tln_com_zpad2(obj.getDate()) + " " + "00:00:00";
}
}
//機能IDを返す(Ver3.2用)
function tln_com_func_id() {
if (_FUNC_ID == '') {
_FUNC_ID = TALON.getUserInfoMap().get("FUNC_ID");
}
return _FUNC_ID;
}
//ログインユーザーIDを返す
function tln_com_user_id() {
if (_USER_ID == '') {
var lineDataMap = TALON.getUserInfoMap();
_USER_ID = lineDataMap['USER_ID'];
}
return _USER_ID;
}
//ログファイルに出力
function tln_com_log(val) {
var log = TALON.getLogger();
log.writeDebug(val);
}
//指定文字数でカット
function tln_com_lcut(str,len) {
return str.substring( 0 , len );
}
//ゼロ詰め(2けた)
function tln_com_zpad2(str) {
return ( '0' + str ).slice( -2 );
}
//
function tln_timestamp(str) {
var val = str;
var regExp = new RegExp( "-", "g" ) ;
val = val.replace( regExp , "/" ) ;
var val1 = val.split(" ")[0];
var val2 = val.split(" ")[1];
var val2h = val2.split(":")[0];
var val2m = val2.split(":")[1];
var val2s = val2.split(":")[2];
return val1 + " " + val2h + ":" + val2m + ":" + val2s;
}
//-------------------------------------------
//[部品]消費税率
//-------------------------------------------
function getTAX_RATE(_KIJUN) {
var itemSelectList = TALON.select( "SELECT VLTAXRATE FROM ZT060 WHERE TLN_DATE_TO_CHAR('YMD', DTSTART) <= '" + _KIJUN + "' ORDER BY DTSTART DESC " );
var lineDataMap = itemSelectList[0];
var val = lineDataMap['VLTAXRATE'];
//var val = 0.08;
return val;
}
//-------------------------------------------
//[部品]会計年度・月序 チェック
//-------------------------------------------
function checkNENDO(_NENDO,GMSEQ) {
var itemSelectList = TALON.select( "SELECT TXVALUE FROM ZT010 WHERE IDVARIANT = 'ALLOWED_FISCAL_MONTH' " );
var lineDataMap = itemSelectList[0];
var _ALLOWED_FISCAL_MONTH = lineDataMap['TXVALUE'];
if ( ( ( _NENDO * 100 ) + GMSEQ ) < parseInt(_ALLOWED_FISCAL_MONTH) ) {
TALON.addErrorMsg( "すでに会計締め処理済み取引日のため処理できません" );
TALON.setIsSuccess(false);
}
return true;
}
//-------------------------------------------
//[部品]会計年度
//パラメータ基準日(YYYY/MM/DD)
//-------------------------------------------
function getNENDO(BASE_DATE) {
var regExp = new RegExp( "-", "g" ) ;
BASE_DATE = tln_com_date2string2(BASE_DATE).replace( regExp , "/" ) ;
var BASE_DATE1 = BASE_DATE.split(" ")[0];
var BASE_DATE2 = BASE_DATE.split(" ")[1];
BASE_DATE = BASE_DATE1
var itemSelectList = TALON.select( "SELECT TXVALUE FROM ZT010 WHERE IDVARIANT = 'FIRST_MONTH' " );
var lineDataMap = itemSelectList[0];
var _FIRST_MONTH = lineDataMap['TXVALUE'];
var itemSelectList = TALON.select( "SELECT TXVALUE FROM ZT010 WHERE IDVARIANT = 'LAST_DAY' " );
var lineDataMap = itemSelectList[0];
var _LAST_DAY = lineDataMap['TXVALUE'];
var _END_MONTH = 0;
var _END_DAY = 0;
//END日を取得
if (_FIRST_MONTH == 1) {
_END_MONTH = 12;
} else {
_END_MONTH = _FIRST_MONTH - 1;
}
if (_LAST_DAY == 31) {
//END_MONTHの最終日(_FIRST_MONTH初日の前日)
var _TEMP = "1999/" + tln_com_zpad2(_FIRST_MONTH) + "/01" + " " + "00:00:00";
var wdate = tln_com_todatetime(_TEMP);
wdate.setMinutes(wdate.getMinutes() - 1);
var tdate = tln_com_date2string2(wdate);
_TEMP = (tdate.toString().split(" ")[0]).substr( 8 , 2 );
_END_DAY = _TEMP;
} else {
if ( ( _END_MONTH == 2 ) && ( _LAST_DAY >= 28 ) ) {
_END_DAY = 28;
} else {
_END_DAY = _LAST_DAY;
}
}
_END_MONTH = tln_com_zpad2(_END_MONTH);
_END_DAY = tln_com_zpad2(_END_DAY);
//TALON.addMsg( _END_MONTH + "/" + _END_DAY );
var _BASE_DATE_NEN = BASE_DATE.split("/")[0];
var _BASE_DATE_BAS = BASE_DATE.split("/")[1] + BASE_DATE.split("/")[2];
if ( (_BASE_DATE_BAS >= '0101' ) && (_BASE_DATE_BAS <= ( _END_MONTH + _END_DAY ) ) ) {
_BASE_DATE_NEN = _BASE_DATE_NEN - 1;
}
//TALON.addMsg( _BASE_DATE_NEN );
return _BASE_DATE_NEN;
}
//-------------------------------------------
//[部品]月例
//パラメータ基準日(YYYY/MM/DD)
//-------------------------------------------
function getGMSEQ(BASE_DATE) {
var regExp = new RegExp( "-", "g" ) ;
BASE_DATE = tln_com_date2string2(BASE_DATE).replace( regExp , "/" ) ;
var BASE_DATE1 = BASE_DATE.split(" ")[0];
var BASE_DATE2 = BASE_DATE.split(" ")[1];
BASE_DATE = BASE_DATE1
var itemSelectList = TALON.select( "SELECT TXVALUE FROM ZT010 WHERE IDVARIANT = 'FIRST_MONTH' " );
var lineDataMap = itemSelectList[0];
var _FIRST_MONTH = lineDataMap['TXVALUE'];
var itemSelectList = TALON.select( "SELECT TXVALUE FROM ZT010 WHERE IDVARIANT = 'LAST_DAY' " );
var lineDataMap = itemSelectList[0];
var _LAST_DAY = lineDataMap['TXVALUE'];
var _BASE_DATE_NEN = BASE_DATE.split("/")[0];
var _BASE_DATE_MON = BASE_DATE.split("/")[1];
var _BASE_DATE_DAY = BASE_DATE.split("/")[2];
//締め日が31の場合はそのまま月で計算
if (parseInt(_LAST_DAY) == 31) {
_BASE_DATE_MON = parseInt(_BASE_DATE_MON);
}
//締め日が31以外で日付が締め日より大きい場合、翌月数字で計算
if ( (parseInt(_LAST_DAY) != 31) && (parseInt(_LAST_DAY) < parseInt(_BASE_DATE_DAY)) ) {
if (_BASE_DATE_MON == 12) {
_BASE_DATE_MON = 1;
} else {
_BASE_DATE_MON = parseInt(_BASE_DATE_MON) + 1;
}
}
//締め日が31以外で日付が締め日より小さい場合、そのままの月数字で計算
if ( (parseInt(_LAST_DAY) != 31) && (parseInt(_LAST_DAY) >= parseInt(_BASE_DATE_DAY)) ) {
_BASE_DATE_MON = parseInt(_BASE_DATE_MON);
}
var REC = 0;
if (parseInt(_FIRST_MONTH) > parseInt(_BASE_DATE_MON)) {
REC = (parseInt(_BASE_DATE_MON) + 12) - (parseInt(_FIRST_MONTH) - 1);
} else {
REC = (parseInt(_BASE_DATE_MON)) - (parseInt(_FIRST_MONTH) - 1);
}
//TALON.addMsg( REC );
return REC;
}
//-------------------------------------------
//[部品]休日チェック(1:休日 / 0:平日)
//-------------------------------------------
function getHOLIDAY_FLG(_KBCALENDAR, _DTOFF) {
var sql =
"SELECT " +
"COUNT(*) AS CNT " +
"FROM ZT070 " +
"WHERE ZT070.KBCALENDAR = '" + _KBCALENDAR + "' " +
" AND ZT070.DTOFF = TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(_DTOFF) + "') "
;
var itemSelectList = TALON.select(sql);
var lineDataMap = itemSelectList[0];
var _CNT = lineDataMap['CNT'];
return _CNT;
}
//-------------------------------------------
//[部品]品目[BT010]
//-------------------------------------------
function selectBT010(_IDHINMOKU) {
var sql =
"SELECT " +
" IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBHINSYU " +
",PRGENKA " +
",PRHANBAI " +
",KBUNIT " +
",KBUNITPUR " +
",VLKANZAN " +
",PRKOUNYU " +
",IDSIIRESAKI " +
",FGZAIKO " +
",FGKOUNYU " +
",FGHANBAI " +
",FGSEIZO " +
",TXTEKIYO " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM BT010 " +
"WHERE IDHINMOKU = '" + _IDHINMOKU + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]仕入先[DT010]
//-------------------------------------------
function selectDT010(_IDSIIRESAKI) {
var sql =
"SELECT " +
" IDSIIRESAKI " +
",KBSIHARAI " +
",TXHURIKOMI " +
",TXTEKIYO " +
",AMKISYUKAIKAKE " +
",AMSIIRE " +
",AMSIHARAI " +
",AMGENKAIKAKE " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM DT010 " +
"WHERE IDSIIRESAKI = '" + _IDSIIRESAKI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateDT010(itemDataList) {
//項目
var itemColNameTbl = [
'IDSIIRESAKI'
,'KBSIHARAI'
,'TXHURIKOMI'
,'TXTEKIYO'
,'AMKISYUKAIKAKE'
,'AMSIIRE'
,'AMSIHARAI'
,'AMGENKAIKAKE'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
var itemSelectList = selectDT010(itemDataList['IDSIIRESAKI']);
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'IDSIIRESAKI' ];
whereList.push(whereTbl1);
TALON.updateByMap( 'DT010', itemDataList , itemColNameTbl , whereList );
}
//-------------------------------------------
//[部品]得意先[ET010]
//-------------------------------------------
function selectET010(_IDTOKUISAKI) {
var sql =
"SELECT " +
" IDTOKUISAKI " +
",TXTANTOUBUSYO " +
",TXTANTOUSYA " +
",TXTANTOUSYASYOKUI " +
",TXTANTOUSYAEMAIL " +
",TXTANTOUSYADENWA " +
",KBSEIKYUHOUSHIKI " +
",TXSIMEBI " +
",KBNYUKINHOUHOU " +
",VLNYUKINSAITO " +
",AMYOSHIN " +
",NRTANTOUJYUGYOIN " +
",TXTEKIYO " +
",AMKISYUURIKAKE " +
",AMURIAGE " +
",AMJYURYO " +
",AMGENURIKAKE " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM ET010 " +
"WHERE IDTOKUISAKI = '" + _IDTOKUISAKI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateET010(itemDataList) {
//項目
var itemColNameTbl = [
'IDTOKUISAKI'
,'TXTANTOUBUSYO'
,'TXTANTOUSYA'
,'TXTANTOUSYASYOKUI'
,'TXTANTOUSYAEMAIL'
,'TXTANTOUSYADENWA'
,'KBSEIKYUHOUSHIKI'
,'TXSIMEBI'
,'KBNYUKINHOUHOU'
,'VLNYUKINSAITO'
,'AMYOSHIN'
,'NRTANTOUJYUGYOIN'
,'TXTEKIYO'
,'AMKISYUURIKAKE'
,'AMURIAGE'
,'AMJYURYO'
,'AMGENURIKAKE'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
var itemSelectList = selectET010(itemDataList['IDTOKUISAKI']);
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'IDTOKUISAKI' ];
whereList.push(whereTbl1);
TALON.updateByMap( 'ET010', itemDataList , itemColNameTbl , whereList );
}
//-------------------------------------------
//[部品]倉庫在庫[FT010]
//-------------------------------------------
function selectFT010(_IDHINMOKU, _CDSOUKO) {
var sql =
"SELECT " +
" IDHINMOKU " +
",CDSOUKO " +
",QTKISYU " +
",QTNYUKO " +
",QTSYUKKO " +
",AMKISYU " +
",AMNYUKO " +
",AMSYUKKO " +
",QTGENZAIKO " +
",AMGENZAIKO " +
",PRGENZAIKO " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT010 " +
"WHERE IDHINMOKU = '" + _IDHINMOKU + "'" +
" AND CDSOUKO = '" + _CDSOUKO + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function selectFT010_CDSOUKO(_CDSOUKO) {
var sql =
"SELECT " +
" IDHINMOKU " +
",CDSOUKO " +
",QTKISYU " +
",QTNYUKO " +
",QTSYUKKO " +
",AMKISYU " +
",AMNYUKO " +
",AMSYUKKO " +
",QTGENZAIKO " +
",AMGENZAIKO " +
",PRGENZAIKO " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT010 " +
"WHERE CDSOUKO = '" + _CDSOUKO + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateFT010(itemDataList) {
//項目
var itemColNameTbl = [
'IDHINMOKU'
,'CDSOUKO'
,'QTKISYU'
,'QTNYUKO'
,'QTSYUKKO'
,'AMKISYU'
,'AMNYUKO'
,'AMSYUKKO'
,'QTGENZAIKO'
,'AMGENZAIKO'
,'PRGENZAIKO'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
//共通
//--------
//現在庫数
itemDataList['QTGENZAIKO'] = itemDataList['QTKISYU'] + itemDataList['QTNYUKO'] - itemDataList['QTSYUKKO'];
//現在庫額
itemDataList['AMGENZAIKO'] = itemDataList['AMKISYU'] + itemDataList['AMNYUKO'] - itemDataList['AMSYUKKO'];
//現在庫単価
if (itemDataList['QTGENZAIKO'] == 0) {
itemDataList['PRGENZAIKO'] = 0;
} else {
itemDataList['PRGENZAIKO'] = itemDataList['AMGENZAIKO'] / itemDataList['QTGENZAIKO'];
}
//データが存在する場合はupdate、存在しない場合はinsert
var itemSelectList = selectFT010(itemDataList['IDHINMOKU'], itemDataList['CDSOUKO']);
if (itemSelectList.length == 0) {
//INSERT
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
TALON.insertByMap( 'FT010', itemDataList , itemColNameTbl );
} else {
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'IDHINMOKU' ];
var whereTbl2 = [ null, '=' , 'CDSOUKO' ];
whereList.push(whereTbl1);
whereList.push(whereTbl2);
TALON.updateByMap( 'FT010', itemDataList , itemColNameTbl , whereList );
}
}
//-------------------------------------------
//[部品]在庫増減履歴[FT100]
//-------------------------------------------
function selectFT100(_NRZAITORI) {
var sql =
"SELECT " +
" NRZAITORI " +
",DTTORIHIKI " +
",KBUKEBARAI " +
",KBZAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",CDSOUKO " +
",TXAITESAKI " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMSAGAKU " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",QTZOUGEN " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT100 " +
"WHERE NRZAITORI = '" + _NRZAITORI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateFT100(itemDataList) {
//項目
var itemColNameTbl = [
'NRZAITORI'
,'DTTORIHIKI'
,'KBUKEBARAI'
,'KBZAIHURI'
,'KBAKADEN'
,'FGVALID'
,'IDHINMOKU'
,'TXHINBAN'
,'TXHINMEI'
,'KBUNIT'
,'CDSOUKO'
,'TXAITESAKI'
,'PRTORIHIKI'
,'QTTORIHIKI'
,'AMTORIHIKI'
,'AMSAGAKU'
,'NRSOURCE'
,'DTCREATE'
,'TXREFNO'
,'DTNEND'
,'DTMSEQ'
,'QTZOUGEN'
,'AMZOUGEN'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
//関連情報補填(採番)
//在庫取引№
var numList = TALON.getNumberingData('XDMF_FF_ZAITORI', 1)
itemDataList['NRZAITORI'] = numList[0];
//関連情報補填(品目マスタ)
var itemSelectList = selectBT010(itemDataList['IDHINMOKU']);
var lineDataMap = itemSelectList[0];
//品番
itemDataList['TXHINBAN'] = lineDataMap['TXHINBAN'];
//品名
itemDataList['TXHINMEI'] = lineDataMap['TXHINMEI'];
//単位区分
itemDataList['KBUNIT'] = lineDataMap['KBUNIT'];
//取引差額
if ( (itemDataList['AMSAGAKU'] == "") || (itemDataList['AMSAGAKU'] == null) ) {
itemDataList['AMSAGAKU'] = 0;
}
//共通
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
var _NENDO = getNENDO(itemDataList['DTTORIHIKI']);
var _GMSEQ = getGMSEQ(itemDataList['DTTORIHIKI']);
checkNENDO(_NENDO, _GMSEQ);
//年度
itemDataList['DTNEND'] = _NENDO;
//月序
itemDataList['DTMSEQ'] = _GMSEQ;
TALON.insertByMap( 'FT100', itemDataList , itemColNameTbl );
}
function insertAkaFT100(_NRZAITORI) {
//関連情報補填(採番)
//在庫取引№
var numList = TALON.getNumberingData('XDMF_FF_ZAITORI', 1)
_NEXT_NRZAITORI = numList[0];
//
TALON.insert(
" INSERT INTO FT100 ( " +
" NRZAITORI " +
" ,DTTORIHIKI " +
" ,KBUKEBARAI " +
" ,KBZAIHURI " +
" ,KBAKADEN " +
" ,FGVALID " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,CDSOUKO " +
" ,TXAITESAKI " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTORIHIKI " +
" ,AMSAGAKU " +
" ,NRSOURCE " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,QTZOUGEN " +
" ,AMZOUGEN " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" ) " +
" SELECT " +
" '" + _NEXT_NRZAITORI + "' " +
" ,DTTORIHIKI " +
" ,KBUKEBARAI " +
" ,KBZAIHURI " +
" ,'2' " +
" ,'F' " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,CDSOUKO " +
" ,TXAITESAKI " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTORIHIKI " +
" ,AMSAGAKU " +
" ,NRSOURCE " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,(QTZOUGEN * -1) " +
" ,(AMZOUGEN * -1) " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,0 " +
" FROM FT100 " +
" WHERE NRZAITORI = '" + _NRZAITORI + "'"
);
}
//-------------------------------------------
//[部品]買掛増減履歴[DT100]
//-------------------------------------------
function selectDT100(_NRKAIKAKE) {
var sql =
"SELECT " +
" NRKAIKAKE " +
",IDSIIRESAKI " +
",DTTORIHIKI " +
",KBKAITORI " +
",KBKAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMTAX " +
",NRSIHARAI " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM DT100 " +
"WHERE NRKAIKAKE = '" + _NRKAIKAKE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateDT100(itemDataList) {
//項目
var itemColNameTbl = [
'NRKAIKAKE'
,'IDSIIRESAKI'
,'DTTORIHIKI'
,'KBKAITORI'
,'KBKAIHURI'
,'KBAKADEN'
,'FGVALID'
,'IDHINMOKU'
,'TXHINBAN'
,'TXHINMEI'
,'KBUNIT'
,'PRTORIHIKI'
,'QTTORIHIKI'
,'AMTORIHIKI'
,'AMTAX'
,'NRSIHARAI'
,'NRSOURCE'
,'DTCREATE'
,'TXREFNO'
,'DTNEND'
,'DTMSEQ'
,'AMZOUGEN'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
//関連情報補填(採番)
//買掛取引№
var numList = TALON.getNumberingData('XDMF_DF_KAIKAKE', 1)
itemDataList['NRKAIKAKE'] = numList[0];
//関連情報補填(品目マスタ) ※品目IDが入っているときのみ
if (itemDataList['IDHINMOKU'] != '') {
var itemSelectList = selectBT010(itemDataList['IDHINMOKU']);
var lineDataMap = itemSelectList[0];
//品番
itemDataList['TXHINBAN'] = lineDataMap['TXHINBAN'];
//品名
itemDataList['TXHINMEI'] = lineDataMap['TXHINMEI'];
//単位区分
itemDataList['KBUNIT'] = lineDataMap['KBUNITPUR'];
}
//共通
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
var _NENDO = getNENDO(itemDataList['DTTORIHIKI']);
var _GMSEQ = getGMSEQ(itemDataList['DTTORIHIKI']);
checkNENDO(_NENDO, _GMSEQ);
//年度
itemDataList['DTNEND'] = _NENDO;
//月序
itemDataList['DTMSEQ'] = _GMSEQ;
TALON.insertByMap( 'DT100', itemDataList , itemColNameTbl );
}
function insertAkaDT100(_NRKAIKAKE) {
//関連情報補填(採番)
//買掛取引№
var numList = TALON.getNumberingData('XDMF_DF_KAIKAKE', 1)
_NEXT_NRKAIKAKE = numList[0];
//
TALON.insert(
" INSERT INTO DT100 ( " +
" NRKAIKAKE " +
" ,IDSIIRESAKI " +
" ,DTTORIHIKI " +
" ,KBKAITORI " +
" ,KBKAIHURI " +
" ,KBAKADEN " +
" ,FGVALID " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTORIHIKI " +
" ,AMTAX " +
" ,NRSIHARAI " +
" ,NRSOURCE " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,AMZOUGEN " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" ) " +
" SELECT " +
" '" + _NEXT_NRKAIKAKE + "' " +
" ,IDSIIRESAKI " +
" ,DTTORIHIKI " +
" ,KBKAITORI " +
" ,KBKAIHURI " +
" ,'2' " +
" ,'F' " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTORIHIKI " +
" ,AMTAX " +
" ,NRSIHARAI " +
" ,NRSOURCE " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,(AMZOUGEN * -1) " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,0 " +
" FROM DT100 " +
" WHERE NRKAIKAKE = '" + _NRKAIKAKE + "'"
);
}
//-------------------------------------------
//[部品]売掛増減履歴[ET100]
//-------------------------------------------
function selectET100(_NRURIKAKE) {
var sql =
"SELECT " +
" NRURIKAKE " +
",IDTOKUISAKI " +
",DTTORIHIKI " +
",KBURITORI " +
",KBURIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTAX " +
",AMGENKA " +
",NRSOURCE " +
",NRSEIKYU " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",AMARARI " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
",AMTORIHIKI " +
"FROM ET100 " +
"WHERE NRURIKAKE = '" + _NRURIKAKE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateET100(itemDataList) {
//項目
var itemColNameTbl = [
'NRURIKAKE'
,'IDTOKUISAKI'
,'DTTORIHIKI'
,'KBURITORI'
,'KBURIHURI'
,'KBAKADEN'
,'FGVALID'
,'IDHINMOKU'
,'TXHINBAN'
,'TXHINMEI'
,'KBUNIT'
,'PRTORIHIKI'
,'QTTORIHIKI'
,'AMTAX'
,'AMGENKA'
,'NRSOURCE'
,'NRSEIKYU'
,'DTCREATE'
,'TXREFNO'
,'DTNEND'
,'DTMSEQ'
,'AMARARI'
,'AMZOUGEN'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
,'AMTORIHIKI'
];
//関連情報補填(採番)
//買掛取引№
var numList = TALON.getNumberingData('XDMF_EF_URIKAKE', 1)
itemDataList['NRURIKAKE'] = numList[0];
//関連情報補填(品目マスタ) ※品目IDが入っているときのみ
if (itemDataList['IDHINMOKU'] != '') {
var itemSelectList = selectBT010(itemDataList['IDHINMOKU']);
var lineDataMap = itemSelectList[0];
//品番
itemDataList['TXHINBAN'] = lineDataMap['TXHINBAN'];
//品名
itemDataList['TXHINMEI'] = lineDataMap['TXHINMEI'];
//単位区分
itemDataList['KBUNIT'] = lineDataMap['KBUNIT'];
}
//共通
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
var _NENDO = getNENDO(itemDataList['DTTORIHIKI']);
var _GMSEQ = getGMSEQ(itemDataList['DTTORIHIKI']);
checkNENDO(_NENDO, _GMSEQ);
//年度
itemDataList['DTNEND'] = _NENDO;
//月序
itemDataList['DTMSEQ'] = _GMSEQ;
TALON.insertByMap( 'ET100', itemDataList , itemColNameTbl );
}
function insertAkaET100(_NRURIKAKE) {
//関連情報補填(採番)
//買掛取引№
var numList = TALON.getNumberingData('XDMF_EF_URIKAKE', 1)
_NEXT_NRURIKAKE = numList[0];
//
TALON.insert(
" INSERT INTO ET100 ( " +
" NRURIKAKE " +
" ,IDTOKUISAKI " +
" ,DTTORIHIKI " +
" ,KBURITORI " +
" ,KBURIHURI " +
" ,KBAKADEN " +
" ,FGVALID " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTAX " +
" ,AMGENKA " +
" ,NRSOURCE " +
" ,NRSEIKYU " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,AMARARI " +
" ,AMZOUGEN " +
" ,AMTORIHIKI " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" ) " +
" SELECT " +
" '" + _NEXT_NRURIKAKE + "' " +
" ,IDTOKUISAKI " +
" ,DTTORIHIKI " +
" ,KBURITORI " +
" ,KBURIHURI " +
" ,'2' " +
" ,'F' " +
" ,IDHINMOKU " +
" ,TXHINBAN " +
" ,TXHINMEI " +
" ,KBUNIT " +
" ,PRTORIHIKI " +
" ,QTTORIHIKI " +
" ,AMTAX " +
" ,AMGENKA " +
" ,NRSOURCE " +
" ,NRSEIKYU " +
" ,DTCREATE " +
" ,TXREFNO " +
" ,DTNEND " +
" ,DTMSEQ " +
" ,AMARARI " +
" ,(AMZOUGEN * -1) " +
" ,AMTORIHIKI " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,TLN_CHAR_TO_DATE('YMDHMS','" + tln_timestamp(tln_com_nowdate_str()) + "') " +
" ,'" + tln_com_user_id() + "' " +
" ,'" + tln_com_func_id() + "' " +
" ,0 " +
" FROM ET100 " +
" WHERE NRURIKAKE = '" + _NRURIKAKE + "'"
);
}
//-------------------------------------------
//[部品]製造指示[JT010]
//-------------------------------------------
function selectJT010(_NRSEIZO) {
var sql =
" SELECT " +
" NRSEIZO " +
" ,IDTOKUISAKI " +
" ,SQSYUKKASAKI " +
" ,TXTYUMONBANGO " +
" ,IDHINMOKU " +
" ,DTNOUKI " +
" ,QTJYUTYU " +
" ,QTSYUKKA " +
" ,QTSEIZO " +
" ,QTKANSEI " +
" ,QTHURYO " +
" ,QTHAIKI " +
" ,AMGENKA " +
" ,PRMITSUMORI " +
" ,PRJYUTYU " +
" ,TXTEKIYO " +
" ,CDSOUKOKAN " +
" ,CDSOUKOZAI " +
" ,DTCREATE " +
" ,DTHAKKO " +
" ,DTSYUKKO " +
" ,DTKANSEI " +
" ,DTSYUKKA " +
" ,DTCANCEL " +
" ,NRSOURCE " +
" ,STSEIZO " +
" ,PRYOTEIGEN " +
" ,AMHANBAI " +
" ,AMARARI " +
" ,PRGENKA " +
" ,TXSEIZOYOTEI " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM JT010 " +
" WHERE JT010.NRSEIZO = '" + _NRSEIZO + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateJT010(itemDataList) {
//項目
var itemColNameTbl = [
'NRSEIZO'
,'IDTOKUISAKI'
,'SQSYUKKASAKI'
,'TXTYUMONBANGO'
,'IDHINMOKU'
,'DTNOUKI'
,'QTJYUTYU'
,'QTSYUKKA'
,'QTSEIZO'
,'QTKANSEI'
,'QTHURYO'
,'QTHAIKI'
,'AMGENKA'
,'PRMITSUMORI'
,'PRJYUTYU'
,'TXTEKIYO'
,'CDSOUKOKAN'
,'CDSOUKOZAI'
,'DTCREATE'
,'DTHAKKO'
,'DTSYUKKO'
,'DTKANSEI'
,'DTSYUKKA'
,'DTCANCEL'
,'NRSOURCE'
,'STSEIZO'
,'PRYOTEIGEN'
,'AMHANBAI'
,'AMARARI'
,'PRGENKA'
,'TXSEIZOYOTEI'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
var itemSelectList = selectJT010(itemDataList['NRSEIZO']);
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'NRSEIZO' ];
whereList.push(whereTbl1);
TALON.updateByMap( 'JT010', itemDataList , itemColNameTbl , whereList );
}
//-------------------------------------------
//[部品]製造指示工程明細[JT030]
//-------------------------------------------
function selectJT030(_NRSEIZO) {
var sql =
" SELECT " +
" JT030.NRSEIZO " +
" ,JT030.SQKOUTEI " +
" ,JT030.CDKOUTEI " +
" ,JT030.SQCENTER " +
" ,JT030.LTSEIZO " +
" ,JT030.DTFROM " +
" ,JT030.TMFROM " +
" ,JT030.DTTHRU " +
" ,JT030.TMTHRU " +
" ,JT030.SQLIST " +
" ,JT030.TXSAGYOYOTEI " +
" ,JT030.AMKAKOU " +
" ,JT030.CREATED_DATE " +
" ,JT030.CREATED_BY " +
" ,JT030.CREATED_PRG_NM " +
" ,JT030.UPDATED_DATE " +
" ,JT030.UPDATED_BY " +
" ,JT030.UPDATED_PRG_NM " +
" ,JT030.MODIFY_COUNT " +
" ,BT060.RTKAKOU " +
" FROM JT030 " +
" INNER JOIN BT060 " +
" ON BT060.CDKOUTEI = JT030.CDKOUTEI " +
" AND BT060.SQCENTER = JT030.SQCENTER " +
" WHERE JT030.NRSEIZO = '" + _NRSEIZO + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateJT030(itemDataList) {
//項目
var itemColNameTbl = [
'NRSEIZO'
,'SQKOUTEI'
,'CDKOUTEI'
,'SQCENTER'
,'LTSEIZO'
,'DTFROM'
,'TMFROM'
,'DTTHRU'
,'TMTHRU'
,'SQLIST'
,'TXSAGYOYOTEI'
,'AMKAKOU'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
var itemSelectList = selectJT030(itemDataList['NRSEIZO']);
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'NRSEIZO' ];
var whereTbl2 = [ null, '=' , 'SQKOUTEI' ];
whereList.push(whereTbl1);
whereList.push(whereTbl2);
TALON.updateByMap( 'JT030', itemDataList , itemColNameTbl , whereList );
}
//-------------------------------------------
//[部品]製造指示材料明細[JT040]
//-------------------------------------------
function selectJT040(_NRSEIZO) {
var sql =
" SELECT " +
" JT040.NRSEIZO " +
" ,JT040.SQZAIRYO " +
" ,JT040.IDHINMOKU " +
" ,JT040.QTTOUNYU " +
" ,JT040.SQKOUTEI " +
" ,JT040.PRYOTEI " +
" ,JT040.PRSYUKKO " +
" ,JT040.SQLIST " +
" ,JT040.CDSOUKO " +
" ,JT040.CREATED_DATE " +
" ,JT040.CREATED_BY " +
" ,JT040.CREATED_PRG_NM " +
" ,JT040.UPDATED_DATE " +
" ,JT040.UPDATED_BY " +
" ,JT040.UPDATED_PRG_NM " +
" ,JT040.MODIFY_COUNT " +
" FROM JT040 " +
" WHERE JT040.NRSEIZO = '" + _NRSEIZO + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]売掛振替[LT010]
//-------------------------------------------
function selectLT010(_NRURIHURI) {
var sql =
" SELECT " +
" NRURIHURI " +
" ,KBURIHURI " +
" ,DTHURIKAE " +
" ,IDTOKUISAKI " +
" ,AMHURIKAE " +
" ,TXTEKIYO " +
" ,NRSEIKYU " +
" ,NRSOURCE " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" ,KBZOUGEN " +
" FROM LT010 " +
" WHERE LT010.NRURIHURI = '" + _NRURIHURI + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]特殊売上[LT020]
//-------------------------------------------
function selectLT020(_NRTOKUURI) {
var sql =
" SELECT " +
" NRTOKUURI " +
",KBTOKUURI " +
",IDTOKUISAKI " +
",SQSYUKKASAKI " +
",DTTORIHIKI " +
",IDHINMOKU " +
",CDSOUKO " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",PRZAIKO " +
",QTZAIKO " +
",TXTEKIYO " +
",NRSOURCE " +
",AMTORIHIKI " +
",AMTAX " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
" FROM LT020 " +
" WHERE LT020.NRTOKUURI = '" + _NRTOKUURI + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]在庫振替[MT010]
//-------------------------------------------
function selectMT010(_NRZAIHURI) {
var sql =
" SELECT " +
" NRZAIHURI " +
" ,CDSOUKO " +
" ,DTHURIKAE " +
" ,KBZOUGEN " +
" ,KBZAIHURI " +
" ,IDHINMOKU " +
" ,PRHURIKAE " +
" ,QTHURIKAE " +
" ,TXTEKIYO " +
" ,NRSOURCE " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT010 " +
" WHERE NRZAIHURI = '" + _NRZAIHURI + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]棚卸指示[MT020]
//-------------------------------------------
function selectMT020(_NRTANAOROSI) {
var sql =
" SELECT " +
" NRTANAOROSI " +
" ,CDSOUKO " +
" ,DTKIJYUN " +
" ,DTKAKUTEI " +
" ,TXTEKIYO " +
" ,NRSOURCE " +
" ,DTKIJYUNWORK " +
" ,STTANAOROSI " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT020 " +
" WHERE NRTANAOROSI = '" + _NRTANAOROSI + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]棚卸指示明細[MT021]
//-------------------------------------------
function selectMT021(_NRTANAOROSI,_IDHINMOKU) {
var sql =
" SELECT " +
" NRTANAOROSI " +
" ,IDHINMOKU " +
" ,PRKIJYUN " +
" ,QTKIJYUN " +
" ,PRJITSUTANA " +
" ,QTJITSUTANA " +
" ,QTDIFF " +
" ,AMDIFF " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT021 " +
" WHERE NRTANAOROSI = '" + _NRTANAOROSI + "' " +
" AND IDHINMOKU = '" + _IDHINMOKU + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateMT021(itemDataList) {
//項目
var itemColNameTbl = [
'NRTANAOROSI'
,'IDHINMOKU'
,'PRKIJYUN'
,'QTKIJYUN'
,'PRJITSUTANA'
,'QTJITSUTANA'
,'QTDIFF'
,'AMDIFF'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
//共通
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
TALON.insertByMap( 'MT021', itemDataList , itemColNameTbl );
}
//-------------------------------------------
//[部品]棚卸指示明細[MT021]
//-------------------------------------------
function selectMT021_NRTANAOROSI(_NRTANAOROSI) {
var sql =
" SELECT " +
" NRTANAOROSI " +
" ,IDHINMOKU " +
" ,PRKIJYUN " +
" ,QTKIJYUN " +
" ,PRJITSUTANA " +
" ,QTJITSUTANA " +
" ,QTDIFF " +
" ,AMDIFF " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT021 " +
" WHERE NRTANAOROSI = '" + _NRTANAOROSI + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]在庫移動指示[MT030]
//-------------------------------------------
function selectMT030(_NRZAIIDOU) {
var sql =
" SELECT " +
" NRZAIIDOU " +
" ,CDSOUKOFROM " +
" ,CDSOUKOTHRU " +
" ,DTSHIJI " +
" ,DTKANRYOU " +
" ,TXTEKIYO " +
" ,NRSOURCE " +
" ,STZAIIDOU " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT030 " +
" WHERE NRZAIIDOU = '" + _NRZAIIDOU + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]在庫移動指示明細[MT031]
//-------------------------------------------
function selectMT031_NRZAIIDOU(_NRZAIIDOU) {
var sql =
" SELECT " +
" NRZAIIDOU " +
" ,IDHINMOKU " +
" ,PRZAIIDOU " +
" ,QTZAIIDOU " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
" FROM MT031 " +
" WHERE NRZAIIDOU = '" + _NRZAIIDOU + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[部品]工程日付計算リバース
//-------------------------------------------
function calcDTTM_R(sBasDy,sBasTm,sLet,_kakof,_kakot,_calender) {
var rec = '';
var flg1 = true;
var flg2 = true;
sBasDy = sBasDy.toString().split(" ")[0];
tln_com_log("☆R[param ]" + sBasDy + " / " + sBasTm + " / " + sLet + " / " + _kakof + " / " + _kakot + " / " + _calender);
//スタート時点の基準日が既に稼働対象外の場合は直近の稼働に変更する
if (_kakot < sBasTm ) {
tln_com_log("☆R[param ] (1)");
sBasTm = _kakot;
}
if (_kakof > sBasTm ) {
tln_com_log("☆R[param ] (2)");
sBasTm = _kakot;
//前日完了
var wdate = tln_com_todatetime(sBasDy + " " + "00:00:00");
wdate.setMinutes(wdate.getMinutes() - 1);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
flg2 = true;
while (flg2){
if (getHOLIDAY_FLG(_calender,sBasDy + ' 00:00:00') == '0') {
flg2 = false;
} else {
wdate = tln_com_todatetime(sBasDy + ' 00:00:00');
wdate.setMinutes(wdate.getMinutes() - 1);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
}
}
}
rec = sBasDy + " " + sBasTm;
while (flg1){
sBasDy = sBasDy.toString().split(" ")[0];
var wdate = tln_com_todatetime(sBasDy + " " + sBasTm);
var wdatl = tln_com_todatetime(sBasDy + " " + sBasTm);
wdatl.setMinutes(wdate.getMinutes() - sLet);
var wdats = tln_com_todatetime(sBasDy + " " + _kakof);
var tdate = tln_com_date2string2(wdatl);
var tDat = tdate.toString().split(" ")[0];
var tTim = tdate.toString().split(" ")[1];
tTim = tln_com_lcut(tTim,5);
tln_com_log("☆R[wdate ]" + wdate);
tln_com_log("☆R[sLet ]" + sLet);
tln_com_log("☆R[wdatl ]" + wdatl);
tln_com_log("☆R[wdats ]" + wdats);
tln_com_log("☆R[tDat ]" + tDat);
tln_com_log("☆R[sBasDy ]" + sBasDy);
tln_com_log("☆R[tTim ]" + tTim);
tln_com_log("☆R[kakof ]" + _kakof);
if (tDat == sBasDy && tTim >= _kakof) {
sBasTm = tTim;
flg1 = false;
} else {
//日付が異なっている場合、もしくは同日でも稼働開始時間より前の開始時刻の場合
//基準から開始日までの時間を計算し残りリードタイムを計算し
//基準日を前日、基準時間を稼働終了時刻にして再度実施
//var sWok = wdats - wdate;
var sWok = getDiff(tln_com_date2string2(wdats),tln_com_date2string2(wdate));
if (sWok < 0) {
sWok = sWok * -1;
}
sLet = sLet - sWok;
tln_com_log("☆R[sWok ]" + sWok);
tln_com_log("☆R[sLet ]" + sLet);
var wdate = tln_com_todatetime(sBasDy + " " + "00:00:00");
wdate.setMinutes(wdate.getMinutes() - 1);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
flg2 = true;
while (flg2){
if (getHOLIDAY_FLG(_calender,sBasDy + ' 00:00:00') == '0') {
flg2 = false;
} else {
wdate = tln_com_todatetime(sBasDy + ' 00:00:00');
wdate.setMinutes(wdate.getMinutes() - 1);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
}
}
sBasTm = _kakot;
}
}
tln_com_log("☆R[return ]" + (sBasDy + " " + sBasTm + "," + rec));
return (sBasDy + " " + sBasTm + "," + rec);
}
//-------------------------------------------
//[部品]工程日付計算フォワード
//返り値:(完了日),(開始日)
//-------------------------------------------
function calcDTTM_F(sBasDy,sBasTm,sLet,_kakof,_kakot,_calender) {
var rec = '';
var flg1 = true;
var flg2 = true;
sBasDy = sBasDy.toString().split(" ")[0];
tln_com_log("☆F[param ]" + sBasDy + " / " + sBasTm + " / " + sLet + " / " + _kakof + " / " + _kakot + " / " + _calender);
//スタート時点の基準日が既に稼働対象外の場合は直近の稼働に変更する
if (_kakof > sBasTm ) {
tln_com_log("☆F[param ] (1)");
sBasTm = _kakof;
}
if (_kakot < sBasTm ) {
tln_com_log("☆F[param ] (2)");
sBasTm = _kakof;
//翌日開始
var wdate = tln_com_todatetime(sBasDy + " " + "23:59:00");
wdate.setMinutes(wdate.getMinutes() + 1);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
flg2 = true;
while (flg2){
if (getHOLIDAY_FLG(_calender,sBasDy + ' 00:00:00') == '0') {
flg2 = false;
} else {
wdate = tln_com_todatetime(sBasDy + ' 23:59:00');
wdate.setMinutes(wdate.getMinutes() + 2);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
}
}
}
rec = sBasDy + " " + sBasTm;
while (flg1){
sBasDy = sBasDy.toString().split(" ")[0];
var wdate = tln_com_todatetime(sBasDy + " " + sBasTm);
var wdatl = tln_com_todatetime(sBasDy + " " + sBasTm);
wdatl.setMinutes(wdate.getMinutes() + sLet);
var wdats = tln_com_todatetime(sBasDy + " " + _kakot);
var tdate = tln_com_date2string2(wdatl);
var tDat = tdate.toString().split(" ")[0];
var tTim = tdate.toString().split(" ")[1];
tTim = tln_com_lcut(tTim,5);
tln_com_log("☆F[wdate ]" + wdate);
tln_com_log("☆F[sLet ]" + sLet);
tln_com_log("☆F[wdatl ]" + wdatl);
tln_com_log("☆F[wdats ]" + wdats);
tln_com_log("☆F[tDat ]" + tDat);
tln_com_log("☆F[sBasDy ]" + sBasDy);
tln_com_log("☆F[tTim ]" + tTim);
tln_com_log("☆F[_kakof ]" + _kakof);
if (tDat == sBasDy && tTim <= _kakot) {
sBasTm = tTim;
flg1 = false;
} else {
//日付が異なっている場合、もしくは同日でも稼働完了時間より先の終了時刻の場合
//基準から終了日までの時間を計算し残りリードタイムを計算し
//基準日を翌日、基準時間を稼働開始時刻にして再度実施
//var sWok = wdats - wdate;
var sWok = getDiff(tln_com_date2string2(wdats),tln_com_date2string2(wdate));
if (sWok < 0) {
sWok = sWok * -1;
}
sLet = sLet - sWok;
tln_com_log("☆F[sWok ]" + sWok);
tln_com_log("☆F[sLet ]" + sLet);
var wdate = tln_com_todatetime(sBasDy + " " + "23:59:00");
wdate.setMinutes(wdate.getMinutes() + 2);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
flg2 = true;
while (flg2){
if (getHOLIDAY_FLG(_calender,sBasDy + ' 00:00:00') == '0') {
flg2 = false;
} else {
wdate = tln_com_todatetime(sBasDy + ' 23:59:00');
wdate.setMinutes(wdate.getMinutes() + 2);
var tdate = tln_com_date2string2(wdate);
sBasDy = tdate.toString().split(" ")[0];
}
}
sBasTm = _kakof;
}
}
tln_com_log("☆R[return ]" + (sBasDy + " " + sBasTm + "," + rec));
return (sBasDy + " " + sBasTm + "," + rec);
}
function getDiff(date1Str, date2Str) {
var date1 = new Date(date1Str);
var date2 = new Date(date2Str);
var msDiff = date2.getTime() - date1.getTime();
var daysDiff = Math.floor(msDiff / (1000 * 60));
return (++daysDiff) - 1;
}
≣ サーバJS ライブラリXDMF_JS002_0 [共通]仕入関連 45996字
//-------------------------------------------
//[処理]入庫処理
//-------------------------------------------
//入庫新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜金額
// 7 : ソース番号
// 8 : 参照番号
function exec_nyuko_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _ZEINUKI_KINGAKU, _NRSOURCE, _TXREFNO) {
//数値準備
var itemSelectList = selectBT010(_HINMOKU);
var lineDataMap = itemSelectList[0];
var _C_SURYO = _SURYO;
var _C_ZEIGAKU = _ZEINUKI_KINGAKU * getTAX_RATE(_TORIHIKIDATE);
var _C_KINGAKU_NUKI = _ZEINUKI_KINGAKU;
var _C_KINGAKU_KOMI = _ZEINUKI_KINGAKU + _C_ZEIGAKU;
var _C_TANKA_NUKI = _C_KINGAKU_NUKI / _C_SURYO;
var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
var _C_SURYO_KEISU = _C_SURYO * lineDataMap['VLKANZAN'];
var _C_TANKA_KOMI_KEISU = _C_KINGAKU_KOMI / _C_SURYO_KEISU;
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = _C_SURYO_KEISU;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = _C_KINGAKU_KOMI;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _C_SURYO_KEISU;
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + _C_KINGAKU_KOMI;
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分 (030 : 仕入入庫)
itemDataList['KBUKEBARAI'] = "030";
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(係数込税込単価)
itemDataList['PRTORIHIKI'] = _C_TANKA_KOMI_KEISU;
//取引数(係数込取引数)
itemDataList['QTTORIHIKI'] = _C_SURYO_KEISU;
//取引額(税込金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU_KOMI;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(係数込取引数)
itemDataList['QTZOUGEN'] = _C_SURYO_KEISU;
//残高増減額(税込金額
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI;
updateFT100(itemDataList);
//買掛履歴作成
//--------------------
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分 (00:入荷仕入)
itemDataList['KBKAITORI'] = "00";
//振替区分 (Null)
itemDataList['KBKAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//取引単価(税抜単価)
itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
//取引数
itemDataList['QTTORIHIKI'] = _C_SURYO;
//税抜取引額(税抜金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
//消費税額
itemDataList['AMTAX'] = _C_ZEIGAKU;
//支払依頼№
itemDataList['NRSIHARAI'] = "";
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減額(税込金額)
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI;
updateDT100(itemDataList);
//仕入先情報更新
//--------------------
var itemDataList = new Array();
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI'];
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI'];
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE'];
//期間仕入額(税込金額)
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] + _C_KINGAKU_KOMI;
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI'];
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE'];
updateDT010(itemDataList);
}
//-------------------------------------------
//入庫取消削除
// 1 : 品目コード
// 2 : 取引先
// 3 : 倉庫
// 4 : 取引日
// 5 : 数量
// 6 : 税抜金額
// 7 : ソース番号
// 8 : 参照番号
//
// * : 在庫取引№
// * : 買掛取引№
function exec_nyuko_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _ZEINUKI_KINGAKU, _NRSOURCE, _TXREFNO,
_NRZAITORI, _NRKAIKAKE) {
//数値準備
// * var itemSelectList = selectBT010(_HINMOKU);
// * var lineDataMap = itemSelectList[0];
// *
// * var _C_SURYO = _SURYO;
// * var _C_ZEIGAKU = _ZEINUKI_KINGAKU * getTAX_RATE(_TORIHIKIDATE);
// * var _C_KINGAKU_NUKI = _ZEINUKI_KINGAKU;
// * var _C_KINGAKU_KOMI = _ZEINUKI_KINGAKU + _C_ZEIGAKU;
// * var _C_TANKA_NUKI = _C_KINGAKU_NUKI / _C_SURYO;
// * var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
// *
// * var _C_SURYO_KEISU = _C_SURYO * lineDataMap['VLKANZAN'];
// * var _C_TANKA_KOMI_KEISU = _C_KINGAKU_KOMI / _C_SURYO_KEISU;
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
var itemSelectList = selectDT100(_NRKAIKAKE);
var lineDataMapDT100 = itemSelectList[0];
var _C_SURYO = lineDataMapDT100['QTTORIHIKI'];
var _C_ZEIGAKU = lineDataMapDT100['AMTAX'];
var _C_KINGAKU_NUKI = lineDataMapDT100['AMTORIHIKI'];
var _C_KINGAKU_KOMI = lineDataMapDT100['AMZOUGEN'];
var _C_TANKA_NUKI = lineDataMapDT100['PRTORIHIKI'];
//var _C_TANKA_KOMI = (使用無し)
var _C_SURYO_KEISU = lineDataMapFT100['QTTORIHIKI'];
var _C_TANKA_KOMI_KEISU = lineDataMapFT100['PRTORIHIKI'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = _C_SURYO_KEISU * -1;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = _C_KINGAKU_KOMI * -1;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + (_C_SURYO_KEISU * -1);
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_C_KINGAKU_KOMI * -1);
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
// * var itemDataList = new Array();
// *
// * //取引日
// * itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
// * //受払区分 (030 : 仕入入庫)
// * itemDataList['KBUKEBARAI'] = "030";
// * //振替区分 (Null)
// * itemDataList['KBZAIHURI'] = "";
// * //赤黒 (2:赤伝)
// * itemDataList['KBAKADEN'] = "2";
// * //効区 (F:無効)
// * itemDataList['FGVALID'] = "F";
// * //品目ID
// * itemDataList['IDHINMOKU'] = _HINMOKU;
// * //倉庫C
// * itemDataList['CDSOUKO'] = _SOUKO;
// * //相手先名
// * itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
// * //取引単価(係数込税込単価)
// * itemDataList['PRTORIHIKI'] = _C_TANKA_KOMI_KEISU;
// * //取引数(係数込取引数)
// * itemDataList['QTTORIHIKI'] = _C_SURYO_KEISU;
// * //取引額(税込金額)
// * itemDataList['AMTORIHIKI'] = _C_KINGAKU_KOMI;
// * //取引ソース№
// * itemDataList['NRSOURCE'] = _NRSOURCE;
// * //登録日時
// * itemDataList['DTCREATE'] = tln_com_nowdate();
// * //参照番号
// * itemDataList['TXREFNO'] = _TXREFNO;
// * //年度(Null)
// * itemDataList['DTNEND'] = '';
// * //月序(Null)
// * itemDataList['DTMSEQ'] = '';
// * //残高増減数(係数込取引数)
// * itemDataList['QTZOUGEN'] = _C_SURYO_KEISU * -1;
// * //残高増減額(税込金額)
// * itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
// *
// * updateFT100(itemDataList);
// *
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + "030" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//買掛履歴作成
//--------------------
// * var itemDataList = new Array();
// *
// * //仕入先ID
// * itemDataList['IDSIIRESAKI'] = _TORIHIKISAKI;
// * //取引日
// * itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
// * //取引区分 (00:入荷仕入)
// * itemDataList['KBKAITORI'] = "00";
// * //振替区分 (Null)
// * itemDataList['KBKAIHURI'] = "";
// * //赤黒 (2:赤伝)
// * itemDataList['KBAKADEN'] = "2";
// * //効区 (F:無効)
// * itemDataList['FGVALID'] = "F";
// * //品目ID
// * itemDataList['IDHINMOKU'] = _HINMOKU;
// * //取引単価(税抜単価)
// * itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
// * //取引数
// * itemDataList['QTTORIHIKI'] = _C_SURYO;
// * //税抜取引額(税抜金額)
// * itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
// * //消費税額(消費税額)
// * itemDataList['AMTAX'] = _C_ZEIGAKU;
// * //支払依頼№
// * itemDataList['NRSIHARAI'] = "";
// * //取引ソース№
// * itemDataList['NRSOURCE'] = _NRSOURCE;
// * //登録日時
// * itemDataList['DTCREATE'] = tln_com_nowdate();
// * //参照番号
// * itemDataList['TXREFNO'] = _TXREFNO;
// * //年度(Null)
// * itemDataList['DTNEND'] = '';
// * //月序(Null)
// * itemDataList['DTMSEQ'] = '';
// * //残高増減額(税込金額)
// * itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
// *
// * updateDT100(itemDataList);
// *
insertAkaDT100(_NRKAIKAKE);
//買掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE DT100 SET " +
" FGVALID = 'F' " +
" WHERE KBKAITORI = '" + "00" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//仕入先情報更新
//--------------------
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI']
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI']
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI']
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO']
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE']
//期間仕入額(税込金額)
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] - _C_KINGAKU_KOMI
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI']
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE']
updateDT010(itemDataList);
}
//-------------------------------------------
//[処理]買掛振替処理
//-------------------------------------------
//買掛振替新規登録
// 1 : 仕入先
// 2 : 取引日
// 3 : 増減区分
// 4 : 振替区分
// 5 : 適用
// 6 : 取引単価
// 7 : ソース番号
// 8 : 参照番号
function exec_kaihuri_ins(_IDSIIRESAKI, _TORIHIKIDATE, _KBZOUGEN, _KBKAIHURI, _TXTEKIYO, _ZEINUKI_HURIKAE, _NRSOURCE, _TXREFNO) {
//数値準備
var _C_SURYO = 1;
var _C_ZEIGAKU = 0;
var _C_KINGAKU_NUKI = _ZEINUKI_HURIKAE;
var _C_KINGAKU_KOMI = _ZEINUKI_HURIKAE + _C_ZEIGAKU;
var _C_TANKA_NUKI = _C_KINGAKU_NUKI / _C_SURYO;
var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
//買掛履歴作成
//--------------------
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = _IDSIIRESAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分
if (_KBZOUGEN == '0') {
//増減区分=0:残高減 → 10:振替控除
itemDataList['KBKAITORI'] = "10";
} else {
//増減区分=1:残高増 → 11:振替計上
itemDataList['KBKAITORI'] = "11";
}
//振替区分 (Null)
itemDataList['KBKAIHURI'] = _KBKAIHURI;
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = '';
//品名/摘要
itemDataList['TXHINMEI'] = _TXTEKIYO;
//単位区分
itemDataList['KBUNIT'] = 'CNT';
//取引単価(税抜単価)
itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
//取引数
itemDataList['QTTORIHIKI'] = _C_SURYO;
//税抜取引額(税抜金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
//消費税額
itemDataList['AMTAX'] = _C_ZEIGAKU;
//支払依頼№
itemDataList['NRSIHARAI'] = "";
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減額(税込金額)
if (_KBZOUGEN == '0') {
//増減区分=0:残高減 → 10:振替控除
var _AMZOUGEN = _C_KINGAKU_KOMI * -1;
} else {
//増減区分=1:残高増 → 11:振替計上
var _AMZOUGEN = _C_KINGAKU_KOMI;
}
itemDataList['AMZOUGEN'] = _AMZOUGEN;
updateDT100(itemDataList);
//仕入先情報更新
//--------------------
//仕入先情報取得
var itemSelectList = selectDT010(_IDSIIRESAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI']
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI']
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI']
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO']
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE']
//期間仕入額(税込金額)
if (_KBZOUGEN == '0') {
//増減区分=0:残高減 → 10:振替控除
var _AMZOUGEN = _C_KINGAKU_KOMI * -1;
} else {
//増減区分=1:残高増 → 11:振替計上
var _AMZOUGEN = _C_KINGAKU_KOMI;
}
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] + _AMZOUGEN
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI']
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE']
updateDT010(itemDataList);
}
//-------------------------------------------
//買掛振替取消削除
// 1 : 仕入先
// 2 : 取引日
// 3 : 増減区分
// 4 : 振替区分
// 5 : 適用
// 6 : 取引単価
// 7 : ソース番号
// 8 : 参照番号
//
// * : 買掛取引№
function exec_kaihuri_del(_IDSIIRESAKI, _TORIHIKIDATE, _KBZOUGEN, _KBKAIHURI, _TXTEKIYO, _ZEINUKI_HURIKAE, _NRSOURCE, _TXREFNO,
_NRKAIKAKE) {
//数量準備
// * var _C_SURYO = 1;
// * var _C_ZEIGAKU = 0;
// * var _C_KINGAKU_NUKI = _ZEINUKI_HURIKAE;
// * var _C_KINGAKU_KOMI = _ZEINUKI_HURIKAE + _C_ZEIGAKU;
// * var _C_TANKA_NUKI = _C_KINGAKU_NUKI / _C_SURYO;
// * var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
var itemSelectList = selectDT100(_NRKAIKAKE);
var lineDataMapDT100 = itemSelectList[0];
var _C_SURYO = lineDataMapDT100['QTTORIHIKI'];
var _C_ZEIGAKU = lineDataMapDT100['AMTAX'];
var _C_KINGAKU_NUKI = lineDataMapDT100['AMTORIHIKI'];
var _C_KINGAKU_KOMI = lineDataMapDT100['AMZOUGEN'];
if (_C_KINGAKU_KOMI < 0 ) {
_C_KINGAKU_KOMI = _C_KINGAKU_KOMI * -1;
}
var _C_TANKA_NUKI = lineDataMapDT100['PRTORIHIKI'];
//var _C_TANKA_KOMI = (使用無し)
//買掛履歴作成
//--------------------
// * var itemDataList = new Array();
// *
// * //仕入先ID
// * itemDataList['IDSIIRESAKI'] = _IDSIIRESAKI;
// * //取引日
// * itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
// * //取引区分
// * if (_KBZOUGEN == '0') {
// * //増減区分=0:残高減 → 10:振替控除
// * itemDataList['KBKAITORI'] = "10";
// * } else {
// * //増減区分=1:残高増 → 11:振替計上
// * itemDataList['KBKAITORI'] = "11";
// * }
// * //振替区分 (Null)
// * itemDataList['KBKAIHURI'] = _KBKAIHURI;
// * //赤黒 (2:赤伝)
// * itemDataList['KBAKADEN'] = "2";
// * //効区 (F:無効)
// * itemDataList['FGVALID'] = "F";
// * //品目ID
// * itemDataList['IDHINMOKU'] = '';
// * //品名/摘要
// * itemDataList['TXHINMEI'] = _TXTEKIYO;
// * //単位区分
// * itemDataList['KBUNIT'] = 'CNT';
// * //取引単価(税抜単価)
// * itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
// * //取引数
// * itemDataList['QTTORIHIKI'] = _C_SURYO;
// * //税抜取引額(税抜金額)
// * itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
// * //消費税額
// * itemDataList['AMTAX'] = _C_ZEIGAKU;
// * //支払依頼№
// * itemDataList['NRSIHARAI'] = "";
// * //取引ソース№
// * itemDataList['NRSOURCE'] = _NRSOURCE;
// * //登録日時
// * itemDataList['DTCREATE'] = tln_com_nowdate();
// * //参照番号
// * itemDataList['TXREFNO'] = _TXREFNO;
// * //年度(Null)
// * itemDataList['DTNEND'] = '';
// * //月序(Null)
// * itemDataList['DTMSEQ'] = '';
// * //残高増減額(税込金額)
// * if (_KBZOUGEN == '0') {
// * //増減区分=0:残高減 → 10:振替控除
// * var _AMZOUGEN = _C_KINGAKU_KOMI * -1;
// * } else {
// * //増減区分=1:残高増 → 11:振替計上
// * var _AMZOUGEN = _C_KINGAKU_KOMI;
// * }
// * itemDataList['AMZOUGEN'] = _AMZOUGEN * -1;
// *
// * updateDT100(itemDataList);
// *
insertAkaDT100(_NRKAIKAKE);
//買掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
if (_KBZOUGEN == '0') {
//増減区分=0:残高減 → 10:振替控除
var _KBKAITORI = "10";
} else {
//増減区分=1:残高増 → 11:振替計上
var _KBKAITORI = "11";
}
TALON.update( " UPDATE DT100 SET " +
" FGVALID = 'F' " +
" WHERE KBKAITORI = '" + _KBKAITORI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//仕入先情報更新
//--------------------
//仕入先情報取得
var itemSelectList = selectDT010(_IDSIIRESAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI']
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI']
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI']
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO']
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE']
//期間仕入額
//期間仕入額(税込金額)
if (_KBZOUGEN == '0') {
//増減区分=0:残高減 → 10:振替控除
var _AMZOUGEN = _C_KINGAKU_KOMI * -1;
} else {
//増減区分=1:残高増 → 11:振替計上
var _AMZOUGEN = _C_KINGAKU_KOMI;
}
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] + (_AMZOUGEN * -1)
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI']
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE']
updateDT010(itemDataList);
}
//-------------------------------------------
//[処理]特殊仕入処理
//-------------------------------------------
//特殊仕入新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 取引区分
// 6 : 取引数
// 7 : 税抜単価
// 8 : 税抜取引額
// 9 : 消費税額
// 10 : ソース番号
// 11 : 参照番号
function exec_tsiire_ins(
_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _KBTOKUSIIRE,
_SURYO, _ZEINUKI_TANKA, _ZEINUKI_KINGAKU, _ZEIGAKU,
_NRSOURCE, _TXREFNO) {
//数値準備
var itemSelectList = selectBT010(_HINMOKU);
var lineDataMap = itemSelectList[0];
var _C_SURYO = _SURYO;
var _C_ZEIGAKU = _ZEIGAKU;
var _C_KINGAKU_NUKI = _ZEINUKI_KINGAKU;
var _C_KINGAKU_KOMI = _ZEINUKI_KINGAKU + _C_ZEIGAKU;
var _C_TANKA_NUKI = _ZEINUKI_TANKA;
var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
var _C_SURYO_KEISU = _C_SURYO * lineDataMap['VLKANZAN'];
var _C_TANKA_KOMI_KEISU = _C_KINGAKU_KOMI / _C_SURYO_KEISU;
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
/*
取引区分=10:仕入返品 → 買掛取引区分=02:仕入返品 →出庫
取引区分=20:直接入荷 → 買掛取引区分=01:直入荷仕入 →入庫
*/
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
if (_KBTOKUSIIRE == '20') {
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = _C_SURYO_KEISU;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = _C_KINGAKU_KOMI;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(係数込取引数)
itemDataList['QTSYUKKO'] = _C_SURYO_KEISU;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(税込金額)
itemDataList['AMSYUKKO'] = _C_KINGAKU_KOMI;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
if (_KBTOKUSIIRE == '20') {
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _C_SURYO_KEISU;
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + _C_KINGAKU_KOMI;
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(係数込取引数)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _C_SURYO_KEISU;
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + _C_KINGAKU_KOMI;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分
//10:仕入返品 → 02:仕入返品 → 140:仕入返品
//20:直接入荷 → 01:直入荷仕入 → 040:直仕入入庫
if (_KBTOKUSIIRE == '20') {
itemDataList['KBUKEBARAI'] = "040";
} else {
itemDataList['KBUKEBARAI'] = "140";
}
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(係数込税込単価)
itemDataList['PRTORIHIKI'] = _C_TANKA_KOMI_KEISU;
//取引数(係数込取引数)
itemDataList['QTTORIHIKI'] = _C_SURYO_KEISU;
//取引額(税込金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU_KOMI;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
if (_KBTOKUSIIRE == '20') {
//20:直接入荷 → 01:直入荷仕入 → 040:直仕入入庫
//残高増減数(係数込税込単価
itemDataList['QTZOUGEN'] = _C_SURYO_KEISU;
//残高増減額(税込金額)
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI;
} else {
//10:仕入返品 → 02:仕入返品 → 140:仕入返品
//残高増減数(係数込税込単価
itemDataList['QTZOUGEN'] = _C_SURYO_KEISU * -1;
//残高増減額(税込金額)
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
}
updateFT100(itemDataList);
//買掛履歴作成
//--------------------
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分
//10:仕入返品 → 02:仕入返品
//20:直接入荷 → 01:直入荷仕入
if (_KBTOKUSIIRE == '20') {
itemDataList['KBKAITORI'] = "01";
} else {
itemDataList['KBKAITORI'] = "02";
}
//振替区分 (Null)
itemDataList['KBKAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//取引単価(税抜単価)
itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
//取引数
itemDataList['QTTORIHIKI'] = _C_SURYO;
//税抜取引額(税抜金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
//消費税額
itemDataList['AMTAX'] = _C_ZEIGAKU;
//支払依頼№
itemDataList['NRSIHARAI'] = "";
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減額(税込金額)
if (_KBTOKUSIIRE == '20') {
//20:直接入荷 → 01:直入荷仕入
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI;
} else {
//10:仕入返品 → 02:仕入返品
itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
}
updateDT100(itemDataList);
//仕入先情報更新
//--------------------
var itemDataList = new Array();
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI'];
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI'];
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE'];
//期間仕入額(税込金額)
if (_KBTOKUSIIRE == '20') {
//20:直接入荷 → 01:直入荷仕入
var _AMSIIRE = _C_KINGAKU_KOMI;
} else {
//10:仕入返品 → 02:仕入返品
var _AMSIIRE = _C_KINGAKU_KOMI * -1;
}
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] + _AMSIIRE;
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI'];
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE'];
updateDT010(itemDataList);
}
//-------------------------------------------
//特殊仕入取消削除
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 取引区分
// 6 : 取引数
// 7 : 税抜単価
// 8 : 税抜取引額
// 9 : 消費税額
// 10 : ソース番号
// 11 : 参照番号
//
// * : 在庫取引№
// * : 買掛取引№
function exec_tsiire_del(
_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _KBTOKUSIIRE,
_SURYO, _ZEINUKI_TANKA, _ZEINUKI_KINGAKU, _ZEIGAKU,
_NRSOURCE, _TXREFNO,
_NRZAITORI, _NRKAIKAKE) {
//数値準備
// * var itemSelectList = selectBT010(_HINMOKU);
// * var lineDataMap = itemSelectList[0];
// *
// * var _C_SURYO = _SURYO;
// * var _C_ZEIGAKU = _ZEIGAKU;
// * var _C_KINGAKU_NUKI = _ZEINUKI_KINGAKU;
// * var _C_KINGAKU_KOMI = _ZEINUKI_KINGAKU + _C_ZEIGAKU;
// * var _C_TANKA_NUKI = _ZEINUKI_TANKA;
// * var _C_TANKA_KOMI = _C_KINGAKU_KOMI / _C_SURYO;
// *
// * var _C_SURYO_KEISU = _C_SURYO * lineDataMap['VLKANZAN'];
// * var _C_TANKA_KOMI_KEISU = _C_KINGAKU_KOMI / _C_SURYO_KEISU;
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
var itemSelectList = selectDT100(_NRKAIKAKE);
var lineDataMapDT100 = itemSelectList[0];
var _C_SURYO = lineDataMapDT100['QTTORIHIKI'];
var _C_ZEIGAKU = lineDataMapDT100['AMTAX'];
var _C_KINGAKU_NUKI = lineDataMapDT100['AMTORIHIKI'];
var _C_KINGAKU_KOMI = lineDataMapDT100['AMZOUGEN'];
if (_C_KINGAKU_KOMI < 0 ) {
_C_KINGAKU_KOMI = _C_KINGAKU_KOMI * -1;
}
var _C_TANKA_NUKI = lineDataMapDT100['PRTORIHIKI'];
//var _C_TANKA_KOMI = (使用無し)
var _C_SURYO_KEISU = lineDataMapFT100['QTTORIHIKI'];
var _C_TANKA_KOMI_KEISU = lineDataMapFT100['PRTORIHIKI'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
/*
取引区分=10:仕入返品 → 買掛取引区分=02:仕入返品 →出庫
取引区分=20:直接入荷 → 買掛取引区分=01:直入荷仕入 →入庫
*/
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
if (_KBTOKUSIIRE == '20') {
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = _C_SURYO_KEISU * -1;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = _C_KINGAKU_KOMI * -1;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(係数込取引数)
itemDataList['QTSYUKKO'] = _C_SURYO_KEISU * -1;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(税込金額)
itemDataList['AMSYUKKO'] = _C_KINGAKU_KOMI * -1;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
if (_KBTOKUSIIRE == '20') {
//期間入庫数(係数込取引数)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + (_C_SURYO_KEISU * -1);
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期間入庫額(税込金額)
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_C_KINGAKU_KOMI * -1);
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(係数込取引数)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_C_SURYO_KEISU * -1);
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(税込金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_C_KINGAKU_KOMI * -1);
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
// * var itemDataList = new Array();
// *
// * //取引日
// * itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
// * //受払区分
// * //10:仕入返品 → 02:仕入返品 → 140:仕入返品
// * //20:直接入荷 → 01:直入荷仕入 → 040:直仕入入庫
// * if (_KBTOKUSIIRE == '20') {
// * itemDataList['KBUKEBARAI'] = "040";
// * } else {
// * itemDataList['KBUKEBARAI'] = "140";
// * }
// * //振替区分 (Null)
// * itemDataList['KBZAIHURI'] = "";
// * //赤黒 (2:赤伝)
// * itemDataList['KBAKADEN'] = "2";
// * //効区 (F:無効)
// * itemDataList['FGVALID'] = "F";
// * //品目ID
// * itemDataList['IDHINMOKU'] = _HINMOKU;
// * //倉庫C
// * itemDataList['CDSOUKO'] = _SOUKO;
// * //相手先名
// * itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
// * //取引単価(係数込税込単価)
// * itemDataList['PRTORIHIKI'] = _C_TANKA_KOMI_KEISU;
// * //取引数(係数込取引数)
// * itemDataList['QTTORIHIKI'] = _C_SURYO_KEISU;
// * //取引額(税込金額)
// * itemDataList['AMTORIHIKI'] = _C_KINGAKU_KOMI;
// * //取引ソース№
// * itemDataList['NRSOURCE'] = _NRSOURCE;
// * //登録日時
// * itemDataList['DTCREATE'] = tln_com_nowdate();
// * //参照番号
// * itemDataList['TXREFNO'] = _TXREFNO;
// * //年度(Null)
// * itemDataList['DTNEND'] = '';
// * //月序(Null)
// * itemDataList['DTMSEQ'] = '';
// * if (_KBTOKUSIIRE == '20') {
// * //20:直接入荷 → 01:直入荷仕入 → 040:直仕入入庫
// * //残高増減数(係数込取引数)
// * itemDataList['QTZOUGEN'] = _C_SURYO_KEISU * -1;
// * //残高増減額(税込金額)
// * itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
// * } else {
// * //10:仕入返品 → 02:仕入返品 → 140:仕入返品
// * //残高増減数(係数込取引数)
// * itemDataList['QTZOUGEN'] = (_C_SURYO_KEISU * -1) * -1;
// * //残高増減額(税込金額)
// * itemDataList['AMZOUGEN'] = (_C_KINGAKU_KOMI * -1) * -1;
// * }
// *
// * updateFT100(itemDataList);
// *
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
if (_KBTOKUSIIRE == '20') {
var _KBUKEBARAI = "040";
} else {
var _KBUKEBARAI = "140";
}
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + _KBUKEBARAI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//買掛履歴作成
//--------------------
// * var itemDataList = new Array();
// *
// * //仕入先ID
// * itemDataList['IDSIIRESAKI'] = _TORIHIKISAKI;
// * //取引日
// * itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
// * //取引区分
// * //10:仕入返品 → 02:仕入返品
// * //20:直接入荷 → 01:直入荷仕入
// * if (_KBTOKUSIIRE == '20') {
// * itemDataList['KBKAITORI'] = "01";
// * } else {
// * itemDataList['KBKAITORI'] = "02";
// * }
// * //振替区分 (Null)
// * itemDataList['KBKAIHURI'] = "";
// * //赤黒 (2:赤伝)
// * itemDataList['KBAKADEN'] = "2";
// * //効区 (F:無効)
// * itemDataList['FGVALID'] = "F";
// * //品目ID
// * itemDataList['IDHINMOKU'] = _HINMOKU;
// * //取引単価(税抜単価)
// * itemDataList['PRTORIHIKI'] = _C_TANKA_NUKI;
// * //取引数
// * itemDataList['QTTORIHIKI'] = _C_SURYO;
// * //税抜取引額(税抜金額)
// * itemDataList['AMTORIHIKI'] = _C_KINGAKU_NUKI;
// * //消費税額
// * itemDataList['AMTAX'] = _C_ZEIGAKU;
// * //支払依頼№
// * itemDataList['NRSIHARAI'] = "";
// * //取引ソース№
// * itemDataList['NRSOURCE'] = _NRSOURCE;
// * //登録日時
// * itemDataList['DTCREATE'] = tln_com_nowdate();
// * //参照番号
// * itemDataList['TXREFNO'] = _TXREFNO;
// * //年度(Null)
// * itemDataList['DTNEND'] = '';
// * //月序(Null)
// * itemDataList['DTMSEQ'] = '';
// * //残高増減額(税込金額)
// * if (_KBTOKUSIIRE == '20') {
// * //20:直接入荷 → 01:直入荷仕入
// * itemDataList['AMZOUGEN'] = _C_KINGAKU_KOMI * -1;
// * } else {
// * //10:仕入返品 → 02:仕入返品
// * itemDataList['AMZOUGEN'] = (_C_KINGAKU_KOMI * -1) * -1;
// * }
// *
// * updateDT100(itemDataList);
// *
insertAkaDT100(_NRKAIKAKE);
//買掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
if (_KBTOKUSIIRE == '20') {
//10:仕入返品 → 02:仕入返品
var _KBKAITORI = "01";
} else {
//20:直接入荷 → 01:直入荷仕入
var _KBKAITORI = "02";
}
TALON.update( " UPDATE DT100 SET " +
" FGVALID = 'F' " +
" WHERE KBKAITORI = '" + _KBKAITORI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//仕入先情報更新
//--------------------
var itemDataList = new Array();
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI']
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI']
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI']
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO']
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE']
//期間仕入額(税込金額)
if (_KBTOKUSIIRE == '20') {
//20:直接入荷 → 01:直入荷仕入
var _AMSIIRE = _C_KINGAKU_KOMI;
} else {
//10:仕入返品 → 02:仕入返品
var _AMSIIRE = _C_KINGAKU_KOMI * -1;
}
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'] + (_AMSIIRE * -1);
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI']
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE']
updateDT010(itemDataList);
}
//-------------------------------------------
//[処理]仕入関連処理
//-------------------------------------------
//-------------------------------------------
//入荷見出し
function selectHT020(_NRNYUKA) {
var sql =
"SELECT " +
" NRNYUKA " +
",IDSIIRESAKI " +
",DTNYUKA " +
",DTKENSYU " +
",CDSOUKO " +
",STNYUKA " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM HT020 " +
"WHERE NRNYUKA = '" + _NRNYUKA + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//発注見出し
function selectHT010(_NRHATTYU) {
var sql =
"SELECT " +
" HT010.NRHATTYU " +
",HT010.IDSIIRESAKI " +
",HT010.DTHATTYU " +
",HT010.DTCREATE " +
",HT010.CDSOUKO " +
",HT010.TXTEKIYO " +
",HT010.STHATTYU " +
",HT010.CREATED_DATE " +
",HT010.CREATED_BY " +
",HT010.CREATED_PRG_NM " +
",HT010.UPDATED_DATE " +
",HT010.UPDATED_BY " +
",HT010.UPDATED_PRG_NM " +
",HT010.MODIFY_COUNT " +
",HT011.QTHATTYU " +
",HT011.QTKENSYU " +
"FROM HT010 " +
"INNER JOIN ( SELECT NRHATTYU, SUM(QTHATTYU) AS QTHATTYU, SUM(QTKENSYU) AS QTKENSYU FROM HT011 GROUP BY NRHATTYU ) HT011 " +
" ON HT011.NRHATTYU = HT010.NRHATTYU " +
"WHERE HT010.NRHATTYU = '" + _NRHATTYU + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
function updateHT010(itemDataList) {
//項目
var itemColNameTbl = [
'NRHATTYU'
,'IDSIIRESAKI'
,'DTHATTYU'
,'DTCREATE'
,'CDSOUKO'
,'TXTEKIYO'
,'STHATTYU'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
var itemSelectList = selectHT010(itemDataList['NRHATTYU']);
var lineDataMap = itemSelectList[0];
var _MODIFY_COUNT = lineDataMap['MODIFY_COUNT'];
//UPDATE
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = (_MODIFY_COUNT + 1);
var whereList = new Array();
var whereTbl1 = [ null, '=' , 'NRHATTYU' ];
whereList.push(whereTbl1);
TALON.updateByMap( 'HT010', itemDataList , itemColNameTbl , whereList );
}
//発注明細(入荷№)
function selectHT011_NRNYUKA(_NRNYUKA) {
var sql =
"SELECT " +
" HT011.NRHATTYU " +
",HT011.SQHATTYU " +
",HT011.IDHINMOKU " +
",HT011.PRHATTYU " +
",HT011.QTHATTYU " +
",HT011.QTKENSYU " +
",HT011.DTNOUKI " +
",HT011.NRNYUKA " +
",HT011.NRSOURCE " +
",HT011.QTKANZAN " +
",HT011.FGNYUKA " +
",HT011.CREATED_DATE " +
",HT011.CREATED_BY " +
",HT011.CREATED_PRG_NM " +
",HT011.UPDATED_DATE " +
",HT011.UPDATED_BY " +
",HT011.UPDATED_PRG_NM " +
",HT011.MODIFY_COUNT " +
",HT010.IDSIIRESAKI " +
",HT010.CDSOUKO " +
"FROM HT011 " +
"INNER JOIN HT010 " +
" ON HT010.NRHATTYU = HT011.NRHATTYU " +
"WHERE NRNYUKA = '" + _NRNYUKA + "' "
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//在庫増減履歴(受払区分+取引ソース番号)
function selectFT100_NRSOURCE(_KBUKEBARAI,_NRSOURCE) {
var sql =
"SELECT " +
" NRZAITORI " +
",DTTORIHIKI " +
",KBUKEBARAI " +
",KBZAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",CDSOUKO " +
",TXAITESAKI " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMSAGAKU " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",QTZOUGEN " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT100 " +
"WHERE KBUKEBARAI = '" + _KBUKEBARAI + "'" +
" AND FGVALID = 'T'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//買掛振替[KT010]
function selectKT010(_NRKAIHURI) {
var sql =
"SELECT " +
" NRKAIHURI " +
",KBKAIHURI " +
",DTHURIKAE " +
",IDSIIRESAKI " +
",AMHURIKAE " +
",TXTEKIYO " +
",NRSOURCE " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
",KBZOUGEN " +
"FROM KT010 " +
"WHERE NRKAIHURI = '" + _NRKAIHURI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//買掛増減履歴(受払区分+取引ソース番号)
function selectDT100_NRSOURCE(_KBKAITORI,_NRSOURCE) {
var sql =
"SELECT " +
" NRKAIKAKE " +
",IDSIIRESAKI " +
",DTTORIHIKI " +
",KBKAITORI " +
",KBKAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMTAX " +
",NRSIHARAI " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM DT100 " +
"WHERE KBKAITORI = '" + _KBKAITORI + "'" +
" AND FGVALID = 'T'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//特殊仕入[KT020]
function selectKT020(_NRTOKUSIIRE) {
var sql =
"SELECT " +
" NRTOKUSIIRE " +
",KBTOKUSIIRE " +
",IDSIIRESAKI " +
",DTTORIHIKI " +
",IDHINMOKU " +
",CDSOUKO " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",PRZAIKO " +
",TXTEKIYO " +
",NRSOURCE " +
",AMTORIHIKI " +
",AMTAX " +
",QTZAITORI " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM KT020 " +
"WHERE NRTOKUSIIRE = '" + _NRTOKUSIIRE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[処理]支払関連
//-------------------------------------------
//支払依頼[DT110]
function selectDT110(_NRSIHARAI) {
var sql =
"SELECT " +
" NRSIHARAI " +
" ,IDSIIRESAKI " +
" ,DTSIHARAI " +
" ,DTSYONIN " +
" ,KBSIHARAI " +
" ,TXSEIKYU " +
" ,TXTEKIYO " +
" ,NRSOURCE " +
" ,AMSIHARAI " +
" ,STSIHARAI " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
"FROM DT110 " +
"WHERE NRSIHARAI = '" + _NRSIHARAI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[処理]支払承認
//-------------------------------------------
// 1 : 仕入先ID
// 2 : 支払承認日
// 3 : 支払依頼額
// 4 : 摘要
// 5 : ソース番号
// 6 : 参照番号
function exec_shiharaisyonin_ins(_TORIHIKISAKI, _TORIHIKIDATE, _AMSIHARAI, _TXTEKIYO , _NRSOURCE, _TXREFNO) {
//買掛履歴作成
//--------------------
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分 (90:支払)
itemDataList['KBKAITORI'] = "90";
//振替区分 (Null)
itemDataList['KBKAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = "";
//品目名/摘要
itemDataList['TXHINMEI'] = _TXTEKIYO;
//取引単価(税抜単価)
itemDataList['PRTORIHIKI'] = _AMSIHARAI;
//取引数
itemDataList['QTTORIHIKI'] = 1;
//税抜取引額(税抜金額)
itemDataList['AMTORIHIKI'] = _AMSIHARAI;
//消費税額
itemDataList['AMTAX'] = 0;
//支払依頼№
itemDataList['NRSIHARAI'] = "";
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減額(税込金額)
itemDataList['AMZOUGEN'] = _AMSIHARAI;
updateDT100(itemDataList);
//仕入先情報更新
//--------------------
var itemDataList = new Array();
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI'];
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI'];
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE'];
//期間仕入額(税込金額)
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE'];
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI'] + _AMSIHARAI;
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE'];
updateDT010(itemDataList);
}
// 1 : 仕入先ID
// 2 : 支払承認日
// 3 : 支払依頼額
// 4 : 摘要
// 5 : ソース番号
// 6 : 参照番号
// * : 買掛取引№
function exec_shiharaisyonin_del(_TORIHIKISAKI, _TORIHIKIDATE, _AMSIHARAI, _TXTEKIYO , _NRSOURCE, _TXREFNO, _NRKAIKAKE) {
//買掛履歴作成
insertAkaDT100(_NRKAIKAKE);
//買掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE DT100 SET " +
" FGVALID = 'F' " +
" WHERE KBKAITORI = '" + "90" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//仕入先情報更新
//--------------------
//仕入先情報取得
var itemSelectList = selectDT010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//仕入先ID
itemDataList['IDSIIRESAKI'] = lineDataMap['IDSIIRESAKI']
//支払方法区分
itemDataList['KBSIHARAI'] = lineDataMap['KBSIHARAI']
//振込銀行口座
itemDataList['TXHURIKOMI'] = lineDataMap['TXHURIKOMI']
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO']
//期首買掛残高
itemDataList['AMKISYUKAIKAKE'] = lineDataMap['AMKISYUKAIKAKE']
//期間仕入額(税込金額)
itemDataList['AMSIIRE'] = lineDataMap['AMSIIRE']
//期間支払額
itemDataList['AMSIHARAI'] = lineDataMap['AMSIHARAI'] - _AMSIHARAI
//現買掛残高
itemDataList['AMGENKAIKAKE'] = lineDataMap['AMGENKAIKAKE']
updateDT010(itemDataList);
}
≣ サーバJS ライブラリXDMF_JS003_0 [共通]製造関連 70763字
//-------------------------------------------
//[処理]出庫処理
//-------------------------------------------
//出庫新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
function exec_syuko_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO) {
//在庫更新
//--------------------
var _QTZOUGEN = _SURYO * -1
var _AMZOUGEN = _KINGAKU * -1
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SURYO;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _KINGAKU;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _SURYO;
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + _KINGAKU;
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分 (160:材料出庫)
itemDataList['KBUKEBARAI'] = "160";
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _TANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _SURYO;
//取引額(金額)
itemDataList['AMTORIHIKI'] = _KINGAKU;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)
itemDataList['QTZOUGEN'] = _QTZOUGEN;
//残高増減額(金額)
itemDataList['AMZOUGEN'] = _AMZOUGEN;
updateFT100(itemDataList);
}
//-------------------------------------------
//出庫取消削除
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
//
// * : 在庫取引№
function exec_syuko_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO,
_NRZAITORI
) {
//数値準備(赤データで再セット)
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
_SURYO = lineDataMapFT100['QTTORIHIKI'];
_KINGAKU = lineDataMapFT100['AMTORIHIKI'];
_TANKA = lineDataMapFT100['PRTORIHIKI'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SURYO * -1;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _KINGAKU * -1;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_SURYO * -1);
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_KINGAKU * -1);
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + "160" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'" +
" AND NRZAITORI = '" + _NRZAITORI + "'"
);
}
//-------------------------------------------
//[処理]完成・出荷(完成入庫)処理
//-------------------------------------------
//完成・出荷入庫新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
function exec_kansei_nyuko_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO) {
//計算
//--------------------
var _C_KINGAKU = _SURYO * _TANKA;
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数(数量)
itemDataList['QTNYUKO'] = _SURYO;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額(金額)
itemDataList['AMNYUKO'] = _C_KINGAKU;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数(数量)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _SURYO;
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額(金額)
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + _C_KINGAKU;
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分 (060 : 完成入庫)
itemDataList['KBUKEBARAI'] = "060";
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _TANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _SURYO;
//取引額(金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)
itemDataList['QTZOUGEN'] = _SURYO;
//残高増減額(金額)
itemDataList['AMZOUGEN'] = _C_KINGAKU;
updateFT100(itemDataList);
}
//-------------------------------------------
//完成出荷入庫取消削除
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
//
// * : 在庫取引№
function exec_kansei_nyuko_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO,
_NRZAITORI) {
//数値準備(赤データで再セット)
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
_SURYO = lineDataMapFT100['QTTORIHIKI'];
_KINGAKU = lineDataMapFT100['AMTORIHIKI'];
_TANKA = lineDataMapFT100['PRTORIHIKI'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数(数量)
itemDataList['QTNYUKO'] = _SURYO * -1;
//期間出庫数
itemDataList['QTSYUKKO'] = 0;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額(金額)
itemDataList['AMNYUKO'] = _KINGAKU * -1;
//期間出庫額
itemDataList['AMSYUKKO'] = 0;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数(数量)
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + (_SURYO * -1);
//期間出庫数
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額(金額)
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_KINGAKU * -1);
//期間出庫額
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + "060" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
}
//-------------------------------------------
//[処理]完成・出荷(廃棄)処理
//-------------------------------------------
//完成・出荷(廃棄)新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
function exec_kansei_haiki_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO) {
//計算
//--------------------
var _C_KINGAKU = _SURYO * _TANKA;
//在庫更新
//--------------------
var _QTZOUGEN = _SURYO * -1
var _AMZOUGEN = _C_KINGAKU * -1
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SURYO;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _C_KINGAKU;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _SURYO;
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + _C_KINGAKU;
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分 (120 : 振替出庫)
itemDataList['KBUKEBARAI'] = "120";
//振替区分 (11:雑損)
itemDataList['KBZAIHURI'] = "11";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _TANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _SURYO;
//取引額(金額)
itemDataList['AMTORIHIKI'] = _C_KINGAKU;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)
itemDataList['QTZOUGEN'] = _QTZOUGEN;
//残高増減額(金額)
itemDataList['AMZOUGEN'] = _AMZOUGEN;
updateFT100(itemDataList);
}
//-------------------------------------------
//完成・出荷(廃棄)取消削除
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量
// 6 : 税抜単価
// 7 : 税抜金額
// 8 : ソース番号
// 9 : 参照番号
//
// * : 在庫取引№
function exec_kansei_haiki_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _SURYO, _TANKA, _KINGAKU, _NRSOURCE, _TXREFNO,
_NRZAITORI) {
//数値準備(赤データで再セット)
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
_SURYO = lineDataMapFT100['QTTORIHIKI'];
_KINGAKU = lineDataMapFT100['AMTORIHIKI'];
_TANKA = lineDataMapFT100['PRTORIHIKI'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SURYO * -1;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _KINGAKU * -1;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_SURYO * -1);
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_KINGAKU * -1);
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + "120" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
}
//-------------------------------------------
//[処理]完成・出荷(販売出荷)処理
//-------------------------------------------
//完成・出荷(販売出荷)新規登録
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量(出荷数)
// 6 : 単価(実勢原価)
// 7 : 単価(受注単価)
// 8 : 実勢原価額
// 9 : ソース番号
// 10 : 参照番号
function exec_kansei_hanbai_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE,
_SYUKA_SURYO, _JISEI_GENKA, _JUCHU_TANKA, _JISEI_KINGAKU,
_NRSOURCE, _TXREFNO) {
//計算
//取引額=実勢原価額
//出荷額
var _C_SYUKA_KINGAKU = _SYUKA_SURYO * _JISEI_GENKA;
var _C_JISEI_KINGAKU = _C_SYUKA_KINGAKU;
//受注金額/消費税額
var _C_JUCHU_KINGAKU_NUKI = _SYUKA_SURYO * _JUCHU_TANKA;
var _C_JUCHU_ZEIGAKU = _C_JUCHU_KINGAKU_NUKI * getTAX_RATE(_TORIHIKIDATE);
var _C_JUCHU_KINGAKU_KOMI = _C_JUCHU_KINGAKU_NUKI + _C_JUCHU_ZEIGAKU;
//在庫更新
//--------------------
var _QTZOUGEN = _SYUKA_SURYO * -1
var _AMZOUGEN = _C_SYUKA_KINGAKU * -1
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SYUKA_SURYO;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _C_SYUKA_KINGAKU;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _SYUKA_SURYO;
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + _C_SYUKA_KINGAKU;
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分 (130 : 売上出庫)
itemDataList['KBUKEBARAI'] = "130";
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _JISEI_GENKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _SYUKA_SURYO;
//取引額(金額)
itemDataList['AMTORIHIKI'] = _C_SYUKA_KINGAKU;
//取引差額 ['(【製造指示】出荷数 *【製造指示】受注単価)-【製造指示】実勢原価額]
itemDataList['AMSAGAKU'] = (_SYUKA_SURYO * _JUCHU_TANKA) - _C_JISEI_KINGAKU;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)
itemDataList['QTZOUGEN'] = _QTZOUGEN;
//残高増減額(金額)
itemDataList['AMZOUGEN'] = _AMZOUGEN;
updateFT100(itemDataList);
//売掛履歴作成
//--------------------
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分(00 : 出荷売上)
itemDataList['KBURITORI'] = "00";
//振替区分(Null)
itemDataList['KBURIHURI'] = "";
//赤黒(1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区(T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//取引単価(受注単価)
itemDataList['PRTORIHIKI'] = _JUCHU_TANKA;
//取引数(出荷数)
itemDataList['QTTORIHIKI'] = _SYUKA_SURYO;
//消費税額(受注金額消費税額)
itemDataList['AMTAX'] = _C_JUCHU_ZEIGAKU;
//販売原価
itemDataList['AMGENKA'] = _C_JISEI_KINGAKU;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//請求№(Null)
itemDataList['NRSEIKYU'] = "";
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//粗利額
itemDataList['AMARARI'] = _C_JUCHU_KINGAKU_NUKI - _C_JISEI_KINGAKU;
//残高増減額
itemDataList['AMZOUGEN'] = _C_JUCHU_KINGAKU_KOMI;
//税抜取引額
itemDataList['AMTORIHIKI'] = _C_JUCHU_KINGAKU_NUKI;
updateET100(itemDataList);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + _C_JUCHU_KINGAKU_KOMI;
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//完成・出荷(販売出荷)取消削除
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 数量(出荷数)
// 6 : 数量(受注数)
// 7 : 単価(実勢原価)
// 8 : 単価(受注単価)
// 9 : 実勢原価額
// 10 : ソース番号
// 11 : 参照番号
//
// * : 在庫取引№
// * : 売掛取引№
function exec_kansei_hanbai_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE,
_SYUKA_SURYO, _JISEI_GENKA, _JUCHU_TANKA, _JISEI_KINGAKU,
_NRSOURCE, _TXREFNO,
_NRZAITORI, _NRURIKAKE) {
//数値準備
// * //出荷額
// * var _C_SYUKA_KINGAKU = _SYUKA_SURYO * _JISEI_GENKA;
// * //受注金額/消費税額
// * var _C_JUCHU_KINGAKU_NUKI = _SYUKA_SURYO * _JUCHU_TANKA;
// * var _C_JUCHU_ZEIGAKU = _C_JUCHU_KINGAKU_NUKI * getTAX_RATE(_TORIHIKIDATE);
// * var _C_JUCHU_KINGAKU_KOMI = _C_JUCHU_KINGAKU_NUKI + _C_JUCHU_ZEIGAKU;
//数値準備(赤データで再セット)
var itemSelectList = selectFT100(_NRZAITORI);
var lineDataMapFT100 = itemSelectList[0];
var itemSelectList = selectET100(_NRURIKAKE);
var lineDataMapET100 = itemSelectList[0];
_SYUKA_SURYO = lineDataMapFT100['QTTORIHIKI'];
_JISEI_GENKA = lineDataMapFT100['PRTORIHIKI'];
var _C_SYUKA_KINGAKU = lineDataMapFT100['AMTORIHIKI'];
var _C_JUCHU_KINGAKU_NUKI = lineDataMapET100['AMTORIHIKI'];
var _C_JUCHU_ZEIGAKU = lineDataMapET100['AMTAX'];
var _C_JUCHU_KINGAKU_KOMI = _C_JUCHU_KINGAKU_NUKI + _C_JUCHU_ZEIGAKU;
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数
itemDataList['QTNYUKO'] = 0;
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = _SYUKA_SURYO * -1;
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額
itemDataList['AMNYUKO'] = 0;
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = _C_SYUKA_KINGAKU * -1;
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
//期間出庫数(数量)
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_SYUKA_SURYO * -1);
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
//期間出庫額(金額)
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_C_SYUKA_KINGAKU * -1);
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + "130" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//売掛履歴作成
//--------------------
insertAkaET100(_NRURIKAKE);
//売掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE ET100 SET " +
" FGVALID = 'F' " +
" WHERE KBURITORI = '" + "00" + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_C_JUCHU_KINGAKU_KOMI * -1);
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//[処理]売掛振替登録処理
//-------------------------------------------
//売掛振替登録処理
// 1 : 取引先コード
// 2 : 取引日
// 3 : 増減区分
// 4 : 振替区分
// 5 : 適用
// 6 : 振替額
// 7 : ソース番号
// 8 : 参照番号(売掛振替№)
function exec_urikake_ins(_TORIHIKISAKI, _TORIHIKIDATE, _ZOGENKBN, _HURIKAEKBN, _TEKIYO, _HURIKAEGAKU,
_NRSOURCE, _TXREFNO) {
//売掛履歴作成
//--------------------
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分(00 : 出荷売上)
if (_ZOGENKBN == '0') {
//10:振替控除
itemDataList['KBURITORI'] = "10";
} else {
//11:振替計上
itemDataList['KBURITORI'] = "11";
}
//振替区分(Null)
itemDataList['KBURIHURI'] = _HURIKAEKBN;
//赤黒(1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区(T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = '';
//品名/摘要
itemDataList['TXHINMEI'] = _TEKIYO;
//単位区分
itemDataList['KBUNIT'] = 'CNT';
//取引単価
itemDataList['PRTORIHIKI'] = _HURIKAEGAKU;
//取引数
itemDataList['QTTORIHIKI'] = 1;
//消費税額
itemDataList['AMTAX'] = 0;
//販売原価
itemDataList['AMGENKA'] = 0;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//請求№(Null)
itemDataList['NRSEIKYU'] = "";
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//粗利額
itemDataList['AMARARI'] = 0;
//残高増減額
//取引区分(00 : 出荷売上)
if (_ZOGENKBN == '0') {
//10:振替控除
itemDataList['AMZOUGEN'] = _HURIKAEGAKU * -1;
} else {
//11:振替計上
itemDataList['AMZOUGEN'] = _HURIKAEGAKU;
}
//税抜取引額
itemDataList['AMTORIHIKI'] = _HURIKAEGAKU;
updateET100(itemDataList);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
if (_ZOGENKBN == '0') {
//10:振替控除
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_HURIKAEGAKU * -1);
} else {
//11:振替計上
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + _HURIKAEGAKU;
}
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//売掛振替削除処理
// 1 : 取引先コード
// 2 : 取引日
// 3 : 増減区分
// 4 : 振替区分
// 5 : 適用
// 6 : 振替額
// 7 : ソース番号
// 8 : 参照番号(売掛振替№)
// * : 売掛取引№
// * : 取引区分
function exec_urikake_del(_TORIHIKISAKI, _TORIHIKIDATE, _ZOGENKBN, _HURIKAEKBN, _TEKIYO, _HURIKAEGAKU,
_NRSOURCE, _TXREFNO, _NRURIKAKE,_KBURITORI) {
//売掛履歴作成
//--------------------
insertAkaET100(_NRURIKAKE);
//売掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE ET100 SET " +
" FGVALID = 'F' " +
" WHERE KBURITORI = '" + _KBURITORI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
//if (_ZOGENKBN == '0') {
if (_KBURITORI == '10') {
//増減区分=0:残高減 → 取引区分=10:振替控除
//10:振替控除
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + ((_HURIKAEGAKU * -1) * -1);
} else {
//11:振替計上
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_HURIKAEGAKU * -1);
}
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//[処理]特殊売上登録処理
//-------------------------------------------
//特殊売上登録処理
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 取引区分
// 6 : 数量
// 7 : 単価
// 8 : 消費税
// 9 税抜取引額
// 10 : 在庫単価
// 11 : 在庫取引数
// 12 : ソース番号
// 13 : 参照番号
function exec_tokuuri_ins(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _TORIHIKIKBN,
_SURYO, _TANKA, _SYOHIZEI, _NUKIGAKU, _ZAIKOTANKA, _ZAIKOTORIHIKISU,
_NRSOURCE, _TXREFNO) {
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_TORIHIKIKBN == '10') {
itemDataList['QTNYUKO'] = _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_TORIHIKIKBN == '10') {
itemDataList['AMNYUKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA);
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_TORIHIKIKBN == '10') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_TORIHIKIKBN == '10') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分
if (_TORIHIKIKBN == '10') {
itemDataList['KBUKEBARAI'] = "050";
} else {
itemDataList['KBUKEBARAI'] = "150";
}
//振替区分 (Null)
itemDataList['KBZAIHURI'] = "";
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _TORIHIKISAKI;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _ZAIKOTANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _ZAIKOTORIHIKISU;
//取引額(金額)
itemDataList['AMTORIHIKI'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//取引差額
itemDataList['AMSAGAKU'] = _NUKIGAKU - (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)/残高増減額(金額)
if (_TORIHIKIKBN == '10') {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
} else {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU * -1;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU) * -1;
}
updateFT100(itemDataList);
//売掛履歴作成
//--------------------
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分
if (_TORIHIKIKBN == '10') {
itemDataList['KBURITORI'] = "02";
} else {
itemDataList['KBURITORI'] = "01";
}
//振替区分(Null)
itemDataList['KBURIHURI'] = "";
//赤黒(1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区(T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//取引単価
itemDataList['PRTORIHIKI'] = _TANKA;
//取引数(出荷数)
itemDataList['QTTORIHIKI'] = _SURYO;
//消費税額
itemDataList['AMTAX'] = _SYOHIZEI;
//販売原価
itemDataList['AMGENKA'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//請求№(Null)
itemDataList['NRSEIKYU'] = "";
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//粗利額
itemDataList['AMARARI'] = _NUKIGAKU - (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//残高増減額
if (_TORIHIKIKBN == '10') {
itemDataList['AMZOUGEN'] = (_NUKIGAKU + _SYOHIZEI) * -1;
} else {
itemDataList['AMZOUGEN'] = _NUKIGAKU + _SYOHIZEI;
}
//税抜取引額
itemDataList['AMTORIHIKI'] = _NUKIGAKU;
updateET100(itemDataList);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
if (_TORIHIKIKBN == '10') {
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + ( (_NUKIGAKU + _SYOHIZEI) * -1 );
} else {
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_NUKIGAKU + _SYOHIZEI);
}
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//特殊売上削除処理
// 1 : 品目コード
// 2 : 取引先コード
// 3 : 倉庫コード
// 4 : 取引日
// 5 : 取引区分
// 6 : 数量
// 7 : 単価
// 8 : 消費税
// 9 税抜取引額
// 10 : 在庫単価
// 11 : 在庫取引数
// 12 : ソース番号
// 13 : 参照番号
//
// * : 在庫取引№
// * : 売掛取引№
function exec_tokuuri_del(_HINMOKU, _TORIHIKISAKI, _SOUKO, _TORIHIKIDATE, _TORIHIKIKBN,
_SURYO, _TANKA, _SYOHIZEI, _NUKIGAKU, _ZAIKOTANKA, _ZAIKOTORIHIKISU,
_NRSOURCE, _TXREFNO,
_NRZAITORI, _NRURIKAKE) {
//数値準備(赤データで再セット)
// * var itemSelectList = selectFT100(_NRZAITORI);
// * var lineDataMapFT100 = itemSelectList[0];
// * _SYUKA_SURYO = lineDataMapFT100['QTTORIHIKI'];
// * _JISEI_GENKA = lineDataMapFT100['PRTORIHIKI'];
// * var _C_SYUKA_KINGAKU = lineDataMapFT100['AMTORIHIKI'];
var itemSelectList = selectET100(_NRURIKAKE);
var lineDataMapET100 = itemSelectList[0];
// * var _C_JUCHU_KINGAKU_NUKI = lineDataMapET100['AMTORIHIKI'];
// * var _C_JUCHU_ZEIGAKU = lineDataMapET100['AMTAX'];
// * var _C_JUCHU_KINGAKU_KOMI = _C_JUCHU_KINGAKU_NUKI + _C_JUCHU_ZEIGAKU;
var _AMZOUGEN = lineDataMapET100['AMZOUGEN'];
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_TORIHIKIKBN == '02') {
itemDataList['QTNYUKO'] = _ZAIKOTORIHIKISU * -1;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _ZAIKOTORIHIKISU * -1;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_TORIHIKIKBN == '02') {
itemDataList['AMNYUKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1;
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1 ;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_TORIHIKIKBN == '02') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + (_ZAIKOTORIHIKISU * -1);
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_ZAIKOTORIHIKISU * -1);
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_TORIHIKIKBN == '02') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + ( (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1);
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + ( (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1) ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
//受払区分
if (_TORIHIKIKBN == '02') {
var _KBUKEBARAI = "050";
} else {
var _KBUKEBARAI = "150";
}
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + _KBUKEBARAI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//売掛履歴作成
//--------------------
insertAkaET100(_NRURIKAKE);
//売掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE ET100 SET " +
" FGVALID = 'F' " +
" WHERE KBURITORI = '" + _TORIHIKIKBN + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
//itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_C_JUCHU_KINGAKU_KOMI * -1);
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'] + (_AMZOUGEN * -1);
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'];
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
//[処理]在庫振替の保守
//-------------------------------------------
//在庫振替登録処理
// 1 : 品目コード
// 2 : 倉庫コード
// 3 : 振替日(取引日)
// 4 : 増減区分
// 4 : 振替区分
// 5 : 取引数量
// 6 : 取引単価
// 7 : ソース番号
// 8 : 参照番号
function exec_zaihuri_ins(_HINMOKU, _SOUKO, _TORIHIKIDATE, _ZOGENKBN, _HURIKAEKBN,
_ZAIKOTORIHIKISU, _ZAIKOTANKA, _NRSOURCE, _TXREFNO) {
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_ZOGENKBN == '1') {
itemDataList['QTNYUKO'] = _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_ZOGENKBN == '1') {
itemDataList['AMNYUKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA);
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_ZOGENKBN == '1') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_ZOGENKBN == '1') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分
if (_ZOGENKBN == '1') {
itemDataList['KBUKEBARAI'] = "020";
} else {
itemDataList['KBUKEBARAI'] = "120";
}
//振替区分 (Null)
itemDataList['KBZAIHURI'] = _HURIKAEKBN;
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = "";
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _ZAIKOTANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _ZAIKOTORIHIKISU;
//取引額(金額)
itemDataList['AMTORIHIKI'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//取引差額
itemDataList['AMSAGAKU'] = 0;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)/残高増減額(金額)
if (_ZOGENKBN == '1') {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
} else {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU * -1;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU) * -1;
}
updateFT100(itemDataList);
}
//-------------------------------------------
//[処理]在庫振替削除
//-------------------------------------------
//在庫振替削除処理
// 1 : 品目コード
// 2 : 倉庫コード
// 3 : 振替日(取引日)
// 5 : 取引数量
// 6 : 取引単価
// 7 : 受払区分
// 7 : ソース番号
// 8 : 参照番号
// * : 在庫取引№
function exec_zaihuri_del(_HINMOKU, _SOUKO, _TORIHIKIDATE, _ZAIKOTORIHIKISU, _ZAIKOTANKA, _KBUKEBARAI,
_NRSOURCE, _TXREFNO, _NRZAITORI) {
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '020') {
itemDataList['QTNYUKO'] = _ZAIKOTORIHIKISU * -1;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _ZAIKOTORIHIKISU * -1;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '020') {
itemDataList['AMNYUKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1;
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1 ;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '020') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + (_ZAIKOTORIHIKISU * -1);
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + (_ZAIKOTORIHIKISU * -1);
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '020') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + ( (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1);
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + ( (_ZAIKOTORIHIKISU * _ZAIKOTANKA) * -1) ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
insertAkaFT100(_NRZAITORI);
//入出庫履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE FT100 SET " +
" FGVALID = 'F' " +
" WHERE KBUKEBARAI = '" + _KBUKEBARAI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
}
//-------------------------------------------
//[処理]在庫振替の保守
//-------------------------------------------
//在庫振替登録処理
// 1 : 品目コード
// 2 : 倉庫コード
// 2 : 相手倉庫コード
// 3 : 振替日(取引日)
// 4 : 受払区分
// 5 : 取引数量
// 6 : 取引単価
// 7 : ソース番号
// 8 : 参照番号
function exec_zaiidou_ins(_HINMOKU, _SOUKO, _AITE_SOUKO, _TORIHIKIDATE, _KBUKEBARAI,
_ZAIKOTORIHIKISU, _ZAIKOTANKA, _NRSOURCE, _TXREFNO) {
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '010') {
itemDataList['QTNYUKO'] = _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '010') {
itemDataList['AMNYUKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA);
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '010') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _ZAIKOTORIHIKISU;
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _ZAIKOTORIHIKISU;
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '010') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + (_ZAIKOTORIHIKISU * _ZAIKOTANKA) ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//受払区分
itemDataList['KBUKEBARAI'] = _KBUKEBARAI;
//振替区分 (Null)
itemDataList['KBZAIHURI'] = null;
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = _AITE_SOUKO;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _ZAIKOTANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _ZAIKOTORIHIKISU;
//取引額(金額)
itemDataList['AMTORIHIKI'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
//取引差額
itemDataList['AMSAGAKU'] = 0;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)/残高増減額(金額)
if (_KBUKEBARAI == '010') {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU);
} else {
itemDataList['QTZOUGEN'] = _ZAIKOTORIHIKISU * -1;
itemDataList['AMZOUGEN'] = (_ZAIKOTANKA * _ZAIKOTORIHIKISU) * -1;
}
updateFT100(itemDataList);
}
//-------------------------------------------
//[処理]棚卸確定更新
//-------------------------------------------
//棚卸確定更新処理
// 1 : 品目コード
// 2 : 倉庫コード
// 4 : 確定日時
// 5 : 実棚数量
// 6 : 基準数量
// 7 : 実棚単価
// 8 : ソース番号
// 9 : 参照番号(棚卸№)
function exec_tanakakutei_ins(_HINMOKU, _SOUKO, _KAKUTEIDATE, _JITSUSU, _KIJUNSU,
_TANKA, _NRSOURCE, _TXREFNO) {
if (_JITSUSU - _KIJUNSU != 0 ) {
if (_JITSUSU == '') { _JITSUSU = 0; }
if (_KIJUNSU == '') { _KIJUNSU = 0; }
if (_TANKA == '') { _TANKA = 0; }
var _KBUKEBARAI = '';
var _QTTORIHIKI = 0;
var _AMTORIHIKI = 0;
var _QTZOUGEN = 0;
var _AMZOUGEN = 0;
if (_JITSUSU - _KIJUNSU > 0 ) {
_KBUKEBARAI = '070';
_QTTORIHIKI = _JITSUSU - _KIJUNSU;
_AMTORIHIKI = (_JITSUSU - _KIJUNSU) * _TANKA;
_QTZOUGEN = _QTTORIHIKI;
_AMZOUGEN = _AMTORIHIKI;
} else {
_KBUKEBARAI = '170';
_QTTORIHIKI = (_JITSUSU - _KIJUNSU) * -1;
_AMTORIHIKI = ((_JITSUSU - _KIJUNSU) * _TANKA) * -1;
_QTZOUGEN = _QTTORIHIKI * -1;
_AMZOUGEN = _AMTORIHIKI * -1;
}
//在庫更新
//--------------------
//現在在庫情報取得
var itemSelectList = selectFT010(_HINMOKU, _SOUKO);
//
var itemDataList = new Array();
if (itemSelectList.length == 0) {
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = 0;
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '070') {
itemDataList['QTNYUKO'] = _QTTORIHIKI;
itemDataList['QTSYUKKO'] = 0;
} else {
itemDataList['QTNYUKO'] = 0;
itemDataList['QTSYUKKO'] = _QTTORIHIKI;
}
//期首在庫額
itemDataList['AMKISYU'] = 0;
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '070') {
itemDataList['AMNYUKO'] = _AMTORIHIKI;
itemDataList['AMSYUKKO'] = 0;
} else {
itemDataList['AMNYUKO'] = 0;
itemDataList['AMSYUKKO'] = _AMTORIHIKI;
}
} else {
var lineDataMap = itemSelectList[0];
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//期首在庫数
itemDataList['QTKISYU'] = lineDataMap['QTKISYU'];
//期間入庫数/期間出庫数(数量)
if (_KBUKEBARAI == '070') {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'] + _QTTORIHIKI;
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'];
} else {
itemDataList['QTNYUKO'] = lineDataMap['QTNYUKO'];
itemDataList['QTSYUKKO'] = lineDataMap['QTSYUKKO'] + _QTTORIHIKI;
}
//期首在庫額
itemDataList['AMKISYU'] = lineDataMap['AMKISYU'];
//期間入庫額/期間出庫額(金額)
if (_KBUKEBARAI == '070') {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'] + _AMTORIHIKI ;
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'];
} else {
itemDataList['AMNYUKO'] = lineDataMap['AMNYUKO'];
itemDataList['AMSYUKKO'] = lineDataMap['AMSYUKKO'] + _AMTORIHIKI ;
}
}
updateFT010(itemDataList);
//入出庫履歴作成
//--------------------
var itemDataList = new Array();
//取引日
itemDataList['DTTORIHIKI'] = _KAKUTEIDATE;
//受払区分
itemDataList['KBUKEBARAI'] = _KBUKEBARAI;
//振替区分 (Null)
itemDataList['KBZAIHURI'] = null;
//赤黒 (1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区 (T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = _HINMOKU;
//倉庫C
itemDataList['CDSOUKO'] = _SOUKO;
//相手先名
itemDataList['TXAITESAKI'] = null;
//取引単価(単価)
itemDataList['PRTORIHIKI'] = _TANKA;
//取引数(数量)
itemDataList['QTTORIHIKI'] = _QTTORIHIKI;
//取引額(金額)
itemDataList['AMTORIHIKI'] = _AMTORIHIKI;
//取引差額
itemDataList['AMSAGAKU'] = 0;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//残高増減数(数量)/残高増減額(金額)
itemDataList['QTZOUGEN'] = _QTZOUGEN;
itemDataList['AMZOUGEN'] = _AMZOUGEN;
updateFT100(itemDataList);
}
}
//-------------------------------------------
//[処理]製造関連処理
//-------------------------------------------
//-------------------------------------------
//製造指示[JT010]
function selectJT010(_NRSEIZO) {
var sql =
"SELECT " +
" NRSEIZO " +
",IDTOKUISAKI " +
",SQSYUKKASAKI " +
",TXTYUMONBANGO " +
",IDHINMOKU " +
",DTNOUKI " +
",QTJYUTYU " +
",QTSYUKKA " +
",QTSEIZO " +
",QTKANSEI " +
",QTHURYO " +
",QTHAIKI " +
",AMGENKA " +
",PRMITSUMORI " +
",PRJYUTYU " +
",TXTEKIYO " +
",CDSOUKOKAN " +
",CDSOUKOZAI " +
",DTCREATE " +
",DTHAKKO " +
",DTSYUKKO " +
",DTKANSEI " +
",DTSYUKKA " +
",DTCANCEL " +
",NRSOURCE " +
",STSEIZO " +
",PRYOTEIGEN " +
",AMHANBAI " +
",AMARARI " +
",PRGENKA " +
",TXSEIZOYOTEI " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM JT010 " +
"WHERE NRSEIZO = '" + _NRSEIZO + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//製造指示材料明細(製造指示番号)[JT040]
function selectJT040_NRSEIZO(_NRSEIZO) {
var sql =
"SELECT " +
" NRSEIZO " +
",SQZAIRYO " +
",IDHINMOKU " +
",QTTOUNYU " +
",SQKOUTEI " +
",PRYOTEI " +
",PRSYUKKO " +
",SQLIST " +
",CDSOUKO " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM JT040 " +
"WHERE NRSEIZO = '" + _NRSEIZO + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//在庫増減履歴
function selectFT100(_NRZAITORI) {
var sql =
"SELECT " +
" NRZAITORI " +
",DTTORIHIKI " +
",KBUKEBARAI " +
",KBZAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",CDSOUKO " +
",TXAITESAKI " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMSAGAKU " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",QTZOUGEN " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT100 " +
"WHERE NRZAITORI = '" + _NRZAITORI + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//在庫増減履歴(受払区分+取引ソース番号)
function selectFT100_NRSOURCE(_KBUKEBARAI,_NRSOURCE) {
var sql =
"SELECT " +
" NRZAITORI " +
",DTTORIHIKI " +
",KBUKEBARAI " +
",KBZAIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",CDSOUKO " +
",TXAITESAKI " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTORIHIKI " +
",AMSAGAKU " +
",NRSOURCE " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",QTZOUGEN " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
"FROM FT100 " +
"WHERE KBUKEBARAI = '" + _KBUKEBARAI + "'" +
" AND FGVALID = 'T'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//売掛増減履歴(受払区分、効区(T)、取引ソース番号)
function selectET100_NRSOURCE(_KBURITORI, _NRSOURCE) {
var sql =
"SELECT " +
" NRURIKAKE " +
",IDTOKUISAKI " +
",DTTORIHIKI " +
",KBURITORI " +
",KBURIHURI " +
",KBAKADEN " +
",FGVALID " +
",IDHINMOKU " +
",TXHINBAN " +
",TXHINMEI " +
",KBUNIT " +
",PRTORIHIKI " +
",QTTORIHIKI " +
",AMTAX " +
",AMGENKA " +
",NRSOURCE " +
",NRSEIKYU " +
",DTCREATE " +
",TXREFNO " +
",DTNEND " +
",DTMSEQ " +
",AMARARI " +
",AMZOUGEN " +
",CREATED_DATE " +
",CREATED_BY " +
",CREATED_PRG_NM " +
",UPDATED_DATE " +
",UPDATED_BY " +
",UPDATED_PRG_NM " +
",MODIFY_COUNT " +
",AMTORIHIKI " +
"FROM ET100 " +
"WHERE KBURITORI = '" + _KBURITORI + "'" +
" AND FGVALID = 'T'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//請求見出し[ET110]
function insertET110(itemDataList) {
//項目
var itemColNameTbl = [
'NRSEIKYU'
,'IDTOKUISAKI'
,'DTSEIKYU'
,'TXTEKIYO'
,'AMSEIKYU'
,'AMNYUKIN'
,'CREATED_DATE'
,'CREATED_BY'
,'CREATED_PRG_NM'
,'UPDATED_DATE'
,'UPDATED_BY'
,'UPDATED_PRG_NM'
,'MODIFY_COUNT'
];
//var numList = TALON.getNumberingData('XDMF_EF_SEIKYU', 1)
//itemDataList['NRSEIKYU'] = numList[0];
//共通
itemDataList['CREATED_DATE'] = tln_com_nowdate();
itemDataList['CREATED_BY'] = tln_com_user_id();
itemDataList['CREATED_PRG_NM'] = tln_com_func_id();
itemDataList['UPDATED_DATE'] = tln_com_nowdate();
itemDataList['UPDATED_BY'] = tln_com_user_id();
itemDataList['UPDATED_PRG_NM'] = tln_com_func_id();
itemDataList['MODIFY_COUNT'] = 1;
TALON.insertByMap( 'ET110', itemDataList , itemColNameTbl );
}
//-------------------------------------------
//[処理]受領関連
//-------------------------------------------
//受領明細[ET120]
function selectET120(_NRJYURYOU) {
var sql =
"SELECT " +
" NRJYURYOU " +
" ,IDTOKUISAKI " +
" ,DTJYURYOU " +
" ,KBKINSYU " +
" ,AMJYURYOU " +
" ,AMTESURYOU " +
" ,NRSOURCE " +
" ,CREATED_DATE " +
" ,CREATED_BY " +
" ,CREATED_PRG_NM " +
" ,UPDATED_DATE " +
" ,UPDATED_BY " +
" ,UPDATED_PRG_NM " +
" ,MODIFY_COUNT " +
"FROM ET120 " +
"WHERE NRJYURYOU = '" + _NRJYURYOU + "'"
;
var itemSelectList = TALON.select(sql);
return itemSelectList;
}
//-------------------------------------------
//[処理]受領処理
//-------------------------------------------
// 1 : 得意先ID
// 2 : 受領日
// 3 : 金種区分
// 4 : 金額(受領金額/残高控除分手数料)
// 5 : 処理区分(1:金額処理/2:手数料処理)
// 5 : 取引ソース№
// 6 : 受領№
function exec_juryo_ins(_TORIHIKISAKI, _TORIHIKIDATE, _KBKINSYU, _KINGAKU, _SYORIKBN,
_NRSOURCE, _TXREFNO) {
//売掛履歴作成
//--------------------
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = _TORIHIKISAKI;
//取引日
itemDataList['DTTORIHIKI'] = _TORIHIKIDATE;
//取引区分
if (_SYORIKBN == '1') {
if (_KBKINSYU == '1') {
itemDataList['KBURITORI'] = "90";
} else if (_KBKINSYU == '2') {
itemDataList['KBURITORI'] = "91";
} else {
itemDataList['KBURITORI'] = "XX";
}
} else {
itemDataList['KBURITORI'] = "92";
}
//振替区分(Null)
itemDataList['KBURIHURI'] = "";
//赤黒(1:黒伝)
itemDataList['KBAKADEN'] = "1";
//効区(T:有効)
itemDataList['FGVALID'] = "T";
//品目ID
itemDataList['IDHINMOKU'] = "";
//単位区分
itemDataList['KBUNIT'] = "CNT";
//取引単価
itemDataList['PRTORIHIKI'] = _KINGAKU;
//取引数
itemDataList['QTTORIHIKI'] = 1;
//消費税額
itemDataList['AMTAX'] = 0;
//販売原価
itemDataList['AMGENKA'] = 0;
//取引ソース№
itemDataList['NRSOURCE'] = _NRSOURCE;
//請求№(Null)
itemDataList['NRSEIKYU'] = "";
//登録日時
itemDataList['DTCREATE'] = tln_com_nowdate();
//参照番号
itemDataList['TXREFNO'] = _TXREFNO;
//年度(Null)
itemDataList['DTNEND'] = '';
//月序(Null)
itemDataList['DTMSEQ'] = '';
//粗利額
itemDataList['AMARARI'] = 0;
//残高増減額
itemDataList['AMZOUGEN'] = _KINGAKU;
//税抜取引額
itemDataList['AMTORIHIKI'] = _KINGAKU;
updateET100(itemDataList);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'];
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'] + _KINGAKU;
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}
//-------------------------------------------
// 1 : 得意先ID
// 2 : 受領日
// 3 : 金種区分
// 4 : 金額(受領金額/残高控除分手数料)
// 5 : 処理区分(1:金額処理/2:手数料処理)
// 5 : 取引ソース№
// 6 : 受領№
// * : 売掛取引№
// * : 取引区分
function exec_juryo_del(_TORIHIKISAKI, _TORIHIKIDATE, _KBKINSYU, _KINGAKU, _SYORIKBN,
_NRSOURCE, _TXREFNO, _NRURIKAKE, _KBURITORI) {
//売掛履歴作成
//--------------------
insertAkaET100(_NRURIKAKE);
//売掛履歴更新
//--------------------
//赤伝発行と共に元黒の効区をF:無効に更新(対象受払区分+取引ソース内で効区は全てFに)
TALON.update( " UPDATE ET100 SET " +
" FGVALID = 'F' " +
" WHERE KBURITORI = '" + _KBURITORI + "'" +
" AND NRSOURCE = '" + _NRSOURCE + "'"
);
//得意先情報更新
//--------------------
var itemDataList = new Array();
//得意先情報取得
var itemSelectList = selectET010(_TORIHIKISAKI);
var lineDataMap = itemSelectList[0];
var itemDataList = new Array();
//得意先ID
itemDataList['IDTOKUISAKI'] = lineDataMap['IDTOKUISAKI'];
//客先担当部署
itemDataList['TXTANTOUBUSYO'] = lineDataMap['TXTANTOUBUSYO'];
//客先担当名
itemDataList['TXTANTOUSYA'] = lineDataMap['TXTANTOUSYA'];
//客先担当職位
itemDataList['TXTANTOUSYASYOKUI'] = lineDataMap['TXTANTOUSYASYOKUI'];
//客先担当メアド
itemDataList['TXTANTOUSYAEMAIL'] = lineDataMap['TXTANTOUSYAEMAIL'];
//客先担当TEL
itemDataList['TXTANTOUSYADENWA'] = lineDataMap['TXTANTOUSYADENWA'];
//請求方式区分
itemDataList['KBSEIKYUHOUSHIKI'] = lineDataMap['KBSEIKYUHOUSHIKI'];
//締め日
itemDataList['TXSIMEBI'] = lineDataMap['TXSIMEBI'];
//標準入金方法区分
itemDataList['KBNYUKINHOUHOU'] = lineDataMap['KBNYUKINHOUHOU'];
//売上入金サイト
itemDataList['VLNYUKINSAITO'] = lineDataMap['VLNYUKINSAITO'];
//与信限度額
itemDataList['AMYOSHIN'] = lineDataMap['AMYOSHIN'];
//担当営業№
itemDataList['NRTANTOUJYUGYOIN'] = lineDataMap['NRTANTOUJYUGYOIN'];
//摘要
itemDataList['TXTEKIYO'] = lineDataMap['TXTEKIYO'];
//期首売掛残高
itemDataList['AMKISYUURIKAKE'] = lineDataMap['AMKISYUURIKAKE'];
//期間売上額(税込金額)
itemDataList['AMURIAGE'] = lineDataMap['AMURIAGE'];
//期間受領額
itemDataList['AMJYURYO'] = lineDataMap['AMJYURYO'] + (_KINGAKU * -1);
//現売掛残高
itemDataList['AMGENURIKAKE'] = lineDataMap['AMGENURIKAKE'];
updateET010(itemDataList);
}