見出し画像

会議室予約アプリで重複予約を禁止にする

やりたいこと

Kintoneで会議室予約アプリを作りたいのですが、予約の重複を禁止する機能はどうやって実現したらいいでしょうか?という相談の続きです。

今回は、同じリソースで既に予約されている日時と重なる予約登録が行われたら、保存ボタンクリック時にエラー表示して登録不可にするという処理です。間違って予約の重複登録してしまうミスを防ぐための措置です。

デモ画面

予約登録重複のエラー処理

上記のデモ画面では、大会議室に2023年10月20日の13時00分~14時30分の予約済のレコードが既にあるため、保存時にエラーにしています。
予約日時の重複チェックのロジックは、以下の通りです。
入力リソース名が同じで且つ(AND)
入力開始時間<予約終了時間 AND 入力終了時間>予約開始時間
図で表すと以下の通りです。
ANDで条件式が成立すると赤枠の範囲に予約時間が被っていると判定することになります。
オレンジ色の予約はエラーで、水色の予約はOKです。

予約日時の重複チェックのロジック

予約重複チェックとエラー処理のJavascriptコード

/* 予約日時の重複をチェックしてエラーにする */
(function() {
    'use strict';

    const RESOURCE_FIELD_CODE = '予約リソース';
    const START_DATE_TIME_FIELD_CODE = '予約開始日時';
    const END_DATE_TIME_FIELD_CODE = '予約終了日時';

    // クエリ検索の実行(予約日時の重複をチェック)
    async function checkOverlap(startDateTime, endDateTime, resource) {
        const appID = kintone.app.getId();
        const query = `${RESOURCE_FIELD_CODE} in ("${resource}") and ${START_DATE_TIME_FIELD_CODE} < "${endDateTime}" and ${END_DATE_TIME_FIELD_CODE} > "${startDateTime}"`;

        try {
            const resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {
                app: appID,
                query: query
            });
            return resp.records.length > 0;
        } catch (error) {
            console.error(error);
        }
    }

    // エラー表示処理
    async function handleEvent(event) {
        const resource = event.record[RESOURCE_FIELD_CODE].value;
        const startDateTime = event.record[START_DATE_TIME_FIELD_CODE].value;
        const endDateTime = event.record[END_DATE_TIME_FIELD_CODE].value;

        if (!startDateTime || !endDateTime || !resource) {
            event.record[RESOURCE_FIELD_CODE].error = '予約リソース、予約開始日時、および予約終了日時を入力してください。';
            return event;
        }

        const isOverlap = await checkOverlap(startDateTime, endDateTime, resource);
        if (isOverlap) {
            event.record[START_DATE_TIME_FIELD_CODE].error = '指定された日時範囲での予約は既に存在します。';
            event.record[END_DATE_TIME_FIELD_CODE].error = '指定された日時範囲での予約は既に存在します。';
        }
        return event;
    }

    // 新規登録でイベント発火する
    kintone.events.on(['app.record.create.submit', handleEvent);
})();

初期設定で3つのフィールドコード名を予約アプリのフォーム設定と合わせて下さい。新規登録画面でのみ動作するようにしています。

※社内リソース予約管理アプリで「編集」を認めると、予約日時の重複チェックに矛盾(編集前のレコードと重複する)が生じるので「編集」権限を禁止する運用をお勧めします。
予約日時を変更したい場合は、削除と再登録する運用がベストです。

<2023/11/13追記>
 編集画面でも、重複チェックのクエリに「編集中のレコードを除外する」条件を追加することで、重複チェックが出来る様になりました。
具体的には、クエリ検索の実行ステップにmyRecordIdを追加して、以下の通り編集中のレコードを除外する条件を追加します。

 // クエリ検索の実行(予約日時の重複をチェック)
   async function checkOverlap(startDateTime, endDateTime, resource, myRecordId) {
       const appID = kintone.app.getId();
       let query = `${RESOURCE_FIELD_CODE} in ("${resource}") and ${START_DATE_TIME_FIELD_CODE} < "${endDateTime}" and ${END_DATE_TIME_FIELD_CODE} > "${startDateTime}"`;
        
// 編集中のレコードを除外する条件を追加
    if (myRecordId) {
        query += ` and $id not in ("${myRecordId}")`;
    }

 新規登録と編集登録でイベントが発火する様に、最後の行も以下の通り変更が必要です。

 // 新規登録と編集登録でイベント発火する
 kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], handleEvent);

実務運用上の課題

 上記のカスタマイズを実施したアプリでは、予約済レコードと予約日時の重複でエラーが出たら、新規登録を一旦キャンセルして、一覧表で予約するリソース(会議室など)の空き時間を調べてから、再度新規登録するという手間が必要になります。
 最初に入力した時間が無駄になる上、画面遷移が必要なので、ユーザーにとっては使い易いアプリとは言えないですね。

フォーム上で予約済リストを表示する

 予約重複でエラーが出た場合、予約リソースの予約状況を新規登録画面のフォーム上で確認出来れば、画面遷移せずに予約日時の重複を避けて登録することができます。
もちろん、予約開始日時を入力する前に「予約表示」ボタンを押して、予約状況を確認してから予約開始、終了日時を入力することも出来ます。
前回のカスタマイズ「会議室予約アプリで予約リストを表示する」との合わせ技で2つのJavascriptコードを登録することで、デモ画面2の様に動作します(操作確認済です)

デモ画面2(重複チェックと予約リスト表示)

予約重複チェックとリスト表示

 当初は、予約の重複エラー処理でだけでは、運用面で難が有るのでお勧め出来なかったカスタマイズですが、新規登録フォーム上で予約状況を確認できるカスタマイズ処理との合わせ技で、実用的なアプリに近づきました。
 「予約日時重複チェック」と「予約リスト表示」の機能を別々のコードに分けているので、コードの保守性も高くなっていると思います。
よろしければ、是非使ってみて下さい。


よろしければサポートお願いします! いただいたサポートは、note記事制作の活動費に使わせていただきます!