diff --git a/src/apps/入金予定結果/index.tsx b/src/apps/入金予定結果/index.tsx index e0f39c9..a72fa00 100644 --- a/src/apps/入金予定結果/index.tsx +++ b/src/apps/入金予定結果/index.tsx @@ -1,6 +1,6 @@ import { eventHnalder } from "@/common/app-template"; import { AppID } from "@/common/appids"; -import { setHeaderButton } from "@/common/header-button"; +import { initMenuBox, setHeaderButton } from "@/common/header-button"; import { KintoneEvent, 値設定 } from "@/common/kintone-event"; import { makeRecordData } from "@/common/rest-api-client"; import { Message } from "@/exception"; @@ -86,16 +86,19 @@ const setData = (event: any, targets: string[]) => { (() => { console.info("script build at " + process.env.BUILD_TIME); - kintone.events.on("app.record.detail.show", (event) => { - const currentRecord = event.record as 入金予定結果; - - // 各種ボタンの設置 - if (currentRecord[入金予定結果フィールド名.残金].value !== "0") { - if (currentRecord.parking_name.value.startsWith("TP")) { - setHeaderButton("テスト充当", getCallbackFillAmount(currentRecord)); + kintone.events.on( + [KintoneEvent.詳細.レコード詳細画面を表示した後], + eventHnalder(async (event) => { + const currentRecord = event.record as 入金予定結果; + await initMenuBox(); + // 各種ボタンの設置 + if (currentRecord[入金予定結果フィールド名.残金].value !== "0") { + if (currentRecord.parking_name.value.startsWith("TP")) { + setHeaderButton("テスト充当", getCallbackFillAmount(currentRecord)); + } } - } - }); + }) + ); const 初回請求金額確定チェック = (record: 入金予定結果) => { if (!record.first_payment_entry_record_no.value) { @@ -150,13 +153,16 @@ const setData = (event: any, targets: string[]) => { await bulkRequest.save(); }; - kintone.events.on(KintoneEvent.追加.レコード追加画面を表示した後, (event) => { - setData(event, [ - 入金予定結果フィールド名.車室契約情報レコード番号, - 入金予定結果フィールド名.初回振り込み関連申込レコード番号, - ]); - return event; - }); + kintone.events.on( + KintoneEvent.追加.レコード追加画面を表示した後, + eventHnalder(async (event) => { + setData(event, [ + 入金予定結果フィールド名.車室契約情報レコード番号, + 入金予定結果フィールド名.初回振り込み関連申込レコード番号, + ]); + return event; + }) + ); kintone.events.on( KintoneEvent.追加.保存するとき, diff --git a/src/apps/定期予約選考/index.ts b/src/apps/定期予約選考/index.ts index 821e277..6f60dfc 100644 --- a/src/apps/定期予約選考/index.ts +++ b/src/apps/定期予約選考/index.ts @@ -1,14 +1,19 @@ import { AppID } from "@/common/appids"; -import { setHeaderButton } from "@/common/header-button"; +import { initMenuBox, setHeaderButton } from "@/common/header-button"; import { makeRecordData } from "@/common/rest-api-client"; import { fillCandidates, noticeToCandidates } from "@/mypage/定期予約選考"; import { 定期予約選考, 定期予約選考フィールド名, + 対象車室一覧行データ, 選考ステータスDropdown, } from "@/types/定期予約選考"; import { 定期申込予約フィールド名, 状態Dropdown } from "@/types/定期申込予約"; import { KintoneRestAPIClient } from "@kintone/rest-api-client"; +import { setup } from ".."; +import { KintoneEvent, サブテーブル設定, 値設定 } from "@/common/kintone-event"; +import { eventHnalder } from "@/common/app-template"; +import { forEach } from "lodash"; // 検索用文字列をセットする const setSearchCondition = (currentRecord: 定期予約選考) => { @@ -109,43 +114,80 @@ const getCallBackHandleFinish = (currentRecord: 定期予約選考) => { }; }; -(() => { - console.info("script build at " + process.env.BUILD_TIME); - - const events = ["app.record.create.show", "app.record.edit.show"]; - kintone.events.on(events, (event) => { - const record = event.record as 定期予約選考; - }); - - kintone.events.on("app.record.detail.show", (event) => { - const currentRecord: 定期予約選考 = event.record; - - // 各種ボタンの設置 - if (currentRecord.選考ステータス.value === 選考ステータスDropdown.起票) { - setHeaderButton( - "候補者設定", - getCallBackHandleFillcandidates(currentRecord) - ); - } - if ( - currentRecord.選考ステータス.value === 選考ステータスDropdown.通知者選択中 - ) { - setHeaderButton( - "通知メール送信", - getCallBackHandleNoticeTocandidates(currentRecord) - ); - } - if ( - currentRecord.選考ステータス.value === 選考ステータスDropdown.候補者仮決定 - ) { - setHeaderButton("当選者確定", getCallBackHandleFinish(currentRecord)); - } - }); - - kintone.events.on("app.record.edit.submit", (event) => { - const currentRecord: 定期予約選考 = event.record; - setSearchCondition(currentRecord); - - return event; - }); -})(); +setup(() => { + kintone.events.on( + [KintoneEvent.追加.レコード追加画面を表示した後], + eventHnalder(async (event) => { + const param = new URLSearchParams(location.search.replace("?", "")); + if (param.has(定期予約選考フィールド名.対象車室一覧_車室レコード番号)) { + const rows = ( + param.get(定期予約選考フィールド名.対象車室一覧_車室レコード番号) ?? + "" + ) + .split(",") + .map((val) => { + return { + 対象車室一覧_車室レコード番号: { + value: val, + // type: "NUMBER", + lookup: true, + }, + }; + }); + + サブテーブル設定(event, 定期予約選考フィールド名.対象車室一覧, rows); + console.log(rows, event); + } + if (param.has(定期予約選考フィールド名.駐車場名)) { + 値設定( + event, + 定期予約選考フィールド名.駐車場名, + param.get(定期予約選考フィールド名.駐車場名) ?? "", + true + ); + } + return event; + }) + ); + + kintone.events.on( + [KintoneEvent.詳細.レコード詳細画面を表示した後], + eventHnalder(async (event) => { + const currentRecord: 定期予約選考 = event.record; + + await initMenuBox(); + // 各種ボタンの設置 + if (currentRecord.選考ステータス.value === 選考ステータスDropdown.起票) { + setHeaderButton( + "候補者設定", + getCallBackHandleFillcandidates(currentRecord) + ); + } + if ( + currentRecord.選考ステータス.value === + 選考ステータスDropdown.通知者選択中 + ) { + setHeaderButton( + "通知メール送信", + getCallBackHandleNoticeTocandidates(currentRecord) + ); + } + if ( + currentRecord.選考ステータス.value === + 選考ステータスDropdown.候補者仮決定 + ) { + setHeaderButton("当選者確定", getCallBackHandleFinish(currentRecord)); + } + }) + ); + + kintone.events.on( + [KintoneEvent.編集.保存するとき], + eventHnalder(async (event) => { + const currentRecord: 定期予約選考 = event.record; + setSearchCondition(currentRecord); + + return event; + }) + ); +}); diff --git a/src/apps/定期申込予約/index.tsx b/src/apps/定期申込予約/index.tsx index ebb0b68..3affc5b 100644 --- a/src/apps/定期申込予約/index.tsx +++ b/src/apps/定期申込予約/index.tsx @@ -1,8 +1,9 @@ +import { apptemplate, eventHnalder } from "@/common/app-template"; import { AppID } from "@/common/appids"; -import { setHeaderButton } from "@/common/header-button"; -import { CancelError, Message } from "@/exception"; +import { initMenuBox, setHeaderButton } from "@/common/header-button"; +import { KintoneEvent } from "@/common/kintone-event"; +import { 契約情報更新イベント } from "@/event/契約情報更新"; import { - ErrorDialog, ShowConfirmDialog, SuccessDialog, WarningDialog, @@ -10,18 +11,16 @@ import { import { getCreateUrl, getDetailUrl } from "@/rest-api/url"; import { 入金予定結果フィールド名 } from "@/types/入金予定結果"; import { 定期申込予約 } from "@/types/定期申込予約"; -import { 申込 } from "./自動承認"; -import { apptemplate } from "@/common/app-template"; import { setup } from ".."; -import { KintoneEvent } from "@/common/kintone-event"; -import { 契約情報更新イベント } from "@/event/契約情報更新"; +import { 申込 } from "./自動承認"; setup(() => { kintone.events.on( [KintoneEvent.詳細.レコード詳細画面を表示した後], - (event) => { + eventHnalder(async (event) => { const record: 定期申込予約 = event.record; + await initMenuBox(); if (!record.auto_confirm_status.value) { setHeaderButton( "自動承認", @@ -69,6 +68,6 @@ setup(() => { }) ); } - } + }) ); }); diff --git a/src/apps/定期駐車場マスタ/index.tsx b/src/apps/定期駐車場マスタ/index.tsx index f9d3c96..c828aea 100644 --- a/src/apps/定期駐車場マスタ/index.tsx +++ b/src/apps/定期駐車場マスタ/index.tsx @@ -1,33 +1,35 @@ -import { apptemplate } from "@/common/app-template"; -import { setHeaderButton } from "@/common/header-button"; +import { apptemplate, eventHnalder } from "@/common/app-template"; +import { initMenuBox, setHeaderButton } from "@/common/header-button"; import { KintoneEvent } from "@/common/kintone-event"; import { 契約状況同期 } from "@/logic/契約状況同期"; import { ShowConfirmDialog, SuccessDialog } from "@/middleware/swal"; import bulkRequest from "@/rest-api/bulk"; import { 定期駐車場マスタ } from "@/types/定期駐車場マスタ"; +import { setup } from ".."; -(() => { - console.info("script build at " + process.env.BUILD_TIME); +setup(() => { + kintone.events.on( + KintoneEvent.詳細.レコード詳細画面を表示した後, + eventHnalder(async (event) => { + const record: 定期駐車場マスタ = event.record; + await initMenuBox(); + setHeaderButton( + "契約状況同期", + apptemplate(async () => { + const confirm = await ShowConfirmDialog({ + text: "契約状況を同期しますか", + }); + if (!confirm.isConfirmed) return; - kintone.events.on(KintoneEvent.詳細.レコード詳細画面を表示した後, (event) => { - const record: 定期駐車場マスタ = event.record; + await 契約状況同期(record.駐車場名.value); - setHeaderButton( - "契約状況同期", - apptemplate(async () => { - const confirm = await ShowConfirmDialog({ - text: "契約状況を同期しますか", - }); - if (!confirm.isConfirmed) return; + await bulkRequest.save(); - await 契約状況同期(record.駐車場名.value); + await SuccessDialog.fire(); - await bulkRequest.save(); - - await SuccessDialog.fire(); - - location.reload(); - }) - ); - }); -})(); + location.reload(); + }) + ); + }) + ); +}); diff --git a/src/apps/車室情報2/index.ts b/src/apps/車室情報2/index.ts new file mode 100644 index 0000000..7ca30f6 --- /dev/null +++ b/src/apps/車室情報2/index.ts @@ -0,0 +1,91 @@ +import { apptemplate, eventHnalder } from "@/common/app-template"; +import { initMenuBox, setHeaderButton } from "@/common/header-button"; +import { KintoneEvent } from "@/common/kintone-event"; +import { + ShowConfirmDialog, + SuccessDialog, + WarningDialog, +} from "@/middleware/swal"; +import { saveReceipt } from "@/mypage/領収証発行"; +import { 領収証 } from "@/types/領収証"; +import { setup } from ".."; +import { 車室情報2, 車室情報2フィールド名 } from "@/types/車室情報2"; +import { 契約状況同期 } from "@/logic/契約状況同期"; +import bulkRequest from "@/rest-api/bulk"; +import { KintoneRestAPIClient } from "@kintone/rest-api-client"; +import { AppID } from "@/common/appids"; +import { QueryBuilder } from "@/rest-api/query"; +import { 定期申込予約フィールド名, 状態Dropdown } from "@/types/定期申込予約"; +import { getCreateUrl } from "@/rest-api/url"; +import { 定期予約選考フィールド名 } from "@/types/定期予約選考"; + +const client = new KintoneRestAPIClient(); + +setup(() => { + const 申込確認 = async (record: 車室情報2) => { + const query = new QueryBuilder(); + query + .whereIn(定期申込予約フィールド名.状態, [ + 状態Dropdown.予約, + 状態Dropdown.空き待ち, + ]) + .where(定期申込予約フィールド名.駐車場名, record.定期駐車場.value); + const { records } = await client.record.getRecords({ + app: AppID.定期申込予約, + query: query.build(), + }); + return records.length !== 0; + }; + + kintone.events.on( + [KintoneEvent.詳細.レコード詳細画面を表示した後], + eventHnalder(async (event) => { + const record = event.record as 車室情報2; + + await initMenuBox(); + // 契約状況同期 + setHeaderButton( + "契約状況同期", + apptemplate(async ({ needReloadAtEnd }) => { + const confirm = await ShowConfirmDialog({ + text: "契約状況を同期しますか", + }); + if (!confirm.isConfirmed) return; + await 契約状況同期( + record.定期駐車場.value, + Number(record.車室番号.value) + ); + await bulkRequest.save(); + await SuccessDialog.fire(); + needReloadAtEnd(true); + }) + ); + + // 選考開始 + setHeaderButton( + "空き募集", + apptemplate(async () => { + // 候補者がいるか確認 + const 申込有無 = await 申込確認(record); + if (!申込有無) { + await WarningDialog.fire({ + title: "申込者がいないため募集できません", + }); + return; + } + + const url = getCreateUrl( + AppID.定期予約選考, + new URLSearchParams({ + [定期予約選考フィールド名.対象車室一覧_車室レコード番号]: + record.$id.value, + [定期予約選考フィールド名.駐車場名]: record.定期駐車場.value, + }) + ); + + window.open(url, "_blank"); + }) + ); + }) + ); +}); diff --git a/src/common/header-button.ts b/src/common/header-button.ts index 79aae66..a9b146e 100644 --- a/src/common/header-button.ts +++ b/src/common/header-button.ts @@ -1,39 +1,64 @@ -export const setHeaderButton = (title: string, onClick: VoidFunction) => { - const interval = setInterval(() => { - const wrapper = document.getElementsByClassName( - "gaia-app-statusbar-actionmenu-wrapper" - )[0]; - - if (wrapper) { - // メニューが存在しなければ作成する - let menu = wrapper.querySelector(".gaia-app-statusbar-actionmenu"); - if (!menu) { - menu = document.createElement("div"); - menu.classList.add(".gaia-app-statusbar-actionmenu"); - wrapper.appendChild(menu); - } +const getWrapper = () => { + const element = document.querySelector( + ".gaia-app-statusbar-actionmenu-wrapper" + ); + + return element; +}; + +const getMenu = () => { + const wrapper = getWrapper(); + if (wrapper === null) return null; - // ステータスバーの表示が無効になっていれば解除する - const statusbar = document.querySelector( - ".gaia-app-statusbar" - ); - if (statusbar) { - statusbar.style.display = "unset"; + const menu = wrapper.querySelector( + ".gaia-app-statusbar-actionmenu" + ); + return menu; +}; +export const initMenuBox = () => { + return new Promise((resolve) => { + const interval = setInterval(() => { + const wrapper = getWrapper(); + + if (wrapper) { + // メニューが存在しなければ作成する + let menu = getMenu(); + if (!menu) { + menu = document.createElement("div"); + menu.classList.add("gaia-app-statusbar-actionmenu"); + wrapper.appendChild(menu); + } + + // ステータスバーの表示が無効になっていれば解除する + const statusbar = document.querySelector( + ".gaia-app-statusbar" + ); + if (statusbar) { + statusbar.style.display = "unset"; + } + + clearInterval(interval); + resolve(); } + }, 50); + }); +}; - const button = document.createElement("span"); - button.classList.add("gaia-app-statusbar-action"); - const label = document.createElement("span"); - label.setAttribute("title", title); - label.innerText = title; - label.classList.add("gaia-app-statusbar-action-label"); +export const setHeaderButton = (title: string, onClick: VoidFunction) => { + console.log("setHeaderButton", title); + const menu = getMenu(); + if (!menu) return; - button.onclick = onClick; + const button = document.createElement("span"); + button.classList.add("gaia-app-statusbar-action"); + const label = document.createElement("span"); + label.setAttribute("title", title); + label.innerText = title; + label.classList.add("gaia-app-statusbar-action-label"); - button.appendChild(label); - menu.appendChild(button); + button.onclick = onClick; - clearInterval(interval); - } - }, 50); + button.appendChild(label); + menu.appendChild(button); + console.log("setHeaderButton", title, "complete"); }; diff --git a/src/common/kintone-event.ts b/src/common/kintone-event.ts index ba3c1a0..909a775 100644 --- a/src/common/kintone-event.ts +++ b/src/common/kintone-event.ts @@ -37,3 +37,29 @@ export const 値設定 = ( event.record[target].lookup = true; } }; + +type サブテーブル設定Props = { + [target: string]: { + value: any; + lookup?: boolean; + }; +}; +export const サブテーブル設定 = ( + event: any, + target: string, + rows: サブテーブル設定Props[] +) => { + const template: any = event.record[target].value[0].value; + const val = rows.map((row) => { + const v: any = {}; + Object.keys(row).forEach((ele) => { + console.log("add", ele, row[ele], template[ele]); + v[ele] = { + ...template[ele], + ...row[ele], + }; + }); + return { value: v }; + }); + event.record[target].value = val; +}; diff --git a/src/rest-api/query.ts b/src/rest-api/query.ts index 797e2d7..087c518 100644 --- a/src/rest-api/query.ts +++ b/src/rest-api/query.ts @@ -21,6 +21,17 @@ export class QueryBuilder { return this; } + whereIn(カラム: string, 条件: string[]) { + const condition = 条件 + .map((val) => { + return sprintf('"%s"', val); + }) + .join(","); + + this.whereConditions.push(sprintf("%s in (%s)", カラム, condition)); + return this; + } + orderBy(カラム: string, 並び: ORDER = "asc") { this.order.push({ カラム, diff --git a/src/types/定期予約選考.ts b/src/types/定期予約選考.ts index 15c3447..aadc0a0 100644 --- a/src/types/定期予約選考.ts +++ b/src/types/定期予約選考.ts @@ -3,9 +3,13 @@ import { AppRecord } from "."; const F = { 選考ステータス: "選考ステータス", + 駐車場名: "駐車場名", 検索用_申込一覧_レコード番号: "検索用_申込一覧_レコード番号", 検索用_契約希望者_レコード番号: "検索用_契約希望者_レコード番号", 検索用_選考結果_レコード番号: "検索用_選考結果_レコード番号", + + 対象車室一覧: "対象車室一覧", + 対象車室一覧_車室レコード番号: "対象車室一覧_車室レコード番号", } as const; export const 選考ステータスDropdown = { @@ -20,6 +24,13 @@ export type 選考ステータスDropdown = (typeof 選考ステータスDropdown)[keyof typeof 選考ステータスDropdown]; export const 定期予約選考フィールド名 = F; + +export type 対象車室一覧行データ = { + 対象車室一覧_車室タイプ?: KintoneRecordField.SingleLineText; + 対象車室一覧_車室番号?: KintoneRecordField.SingleLineText; + [F.対象車室一覧_車室レコード番号]: KintoneRecordField.Number; +}; + export type 定期予約選考 = AppRecord & { 利用開始日: KintoneRecordField.Date; [F.検索用_契約希望者_レコード番号]: KintoneRecordField.SingleLineText; @@ -27,7 +38,7 @@ export type 定期予約選考 = AppRecord & { [F.選考ステータス]: KintoneRecordField.Dropdown; 選考締切日: KintoneRecordField.Date; [F.検索用_申込一覧_レコード番号]: KintoneRecordField.SingleLineText; - 駐車場名: KintoneRecordField.SingleLineText; + [F.駐車場名]: KintoneRecordField.SingleLineText; [F.検索用_選考結果_レコード番号]: KintoneRecordField.SingleLineText; 申込者一覧: KintoneRecordField.Subtable<{ 申込者一覧_申込レコード番号: KintoneRecordField.Number; @@ -41,11 +52,7 @@ export type 定期予約選考 = AppRecord & { 申込者一覧_状態: KintoneRecordField.SingleLineText; 申込者一覧_通知対象: KintoneRecordField.CheckBox; }>; - 対象車室一覧: KintoneRecordField.Subtable<{ - 対象車室一覧_車室タイプ: KintoneRecordField.SingleLineText; - 対象車室一覧_車室番号: KintoneRecordField.SingleLineText; - 対象車室一覧_車室レコード番号: KintoneRecordField.Number; - }>; + [F.対象車室一覧]: KintoneRecordField.Subtable<対象車室一覧行データ>; 選考結果一覧: KintoneRecordField.Subtable<{ 選考結果一覧_氏名: KintoneRecordField.SingleLineText; 選考結果一覧_申込レコード番号: KintoneRecordField.Number; diff --git a/src/types/定期申込予約.ts b/src/types/定期申込予約.ts index eb94c5a..aa53c1d 100644 --- a/src/types/定期申込予約.ts +++ b/src/types/定期申込予約.ts @@ -5,7 +5,7 @@ const F = { 状態: "status", 自動承認ステータス: "auto_confirm_status", 利用開始希望日: "利用開始希望日", - + 駐車場名: "駐車場", 定期駐車料金: "定期駐車料金", 振込期日: "振込期日", 日割り分_月: "日割り分_月", @@ -62,7 +62,7 @@ export type 定期申込予約 = AppRecord & { メモ: KintoneRecordField.MultiLineText; 車室番号: KintoneRecordField.SingleLineText; ParkingNavi駐車場: KintoneRecordField.SingleLineText; - 駐車場: KintoneRecordField.SingleLineText; + [F.駐車場名]: KintoneRecordField.SingleLineText; [F.振込期日]: KintoneRecordField.Date; 日割り分_金額: KintoneRecordField.Number; 自動承認メモ: KintoneRecordField.MultiLineText;