見出し画像

第14話 予約を削除する

こんにちは。Kenです!

すっかり銀杏香る秋になり、肌寒くなりました。今日もお酒を飲みながら執筆していきます。

前回は次回予約確認のプログラムを書きました。

今回は予約を削除するコードを書いていきたいと思います。なお、予約変更したい場合は、あえて変更モードを作るのではなく、予約削除→再度予約としたいと思います。こうしても利用者にそこまで負担がないと思ったからです。

データベースの予約を削除する

さて、前回の終わりに予約データを削除するSQLクエリを実行しましたが、その復習です。

$ heroku pg:psql

でpostgresを立ち上げて

DATABASE=> select * from reservations;

で全予約データを表示させ、

DATABASE=> delete from reservations where id = x;

消したいid番号をxに入れ、実行するとそのデータが消えます。

削除処理の大まかな流れ

今回も処理の起点はお客様が削除したい意思をメッセージで送った場合です。「予約キャンセル」というメッセージを受け取ったら処理をスタートさせたいと思います。

処理の大まかな流れは次のようなものです。

1.「予約キャンセル」というメッセージを受け取る
2.次回予約があるかどうかを確認する
 →ある場合は、4へ
 →ない場合は、3へ
3.「次回予約はありません」といったメッセージをリプライする
4.「??月??日 ??時〜 "メニュー" の予約をキャンセルしますか?」といった確認メッセージをリプライする
5.「はい」で返ってきたpostbackイベントを処理する。処理としては、データベースからの対象予約データの削除。

handleMessageEventの処理追加実装

handleMessageEventの中身を追加実装です。

else if(text === '予約キャンセル'){
     const nextReservation = await checkNextReservation(ev);
     if(nextReservation.length){
       console.log('次回予約があります');
     }else{
       console.log('次回予約なし');
     }
   }

ひとまずこんなコードを作っておきます。checkNextReservationは前回作った未来の予約があるかどうかを確認する関数でした。このように共通で使うコードは関数として外出ししておくと使い回しができるのです。

もし予約があれば、nextReservationに予約オブジェクトが入った配列が返ってきて、予約がなければ何も返ってこない、それを判別してターミナルにメッセージをconsole.logする簡単なプログラムです。

しかし、前回のcheckNextReservationでは未来の予約の有無での処理になっていませんので、checkNextReservationを次のように書き換えます。

const checkNextReservation = (ev) => {
 return new Promise((resolve,reject)=>{
   const id = ev.source.userId;
   const nowTime = new Date().getTime();
   
   const selectQuery = {
     text: 'SELECT * FROM reservations WHERE line_uid = $1 ORDER BY starttime ASC;',
     values: [`${id}`]
   };
   
   connection.query(selectQuery)
     .then(res=>{
       if(res.rows.length){
         const nextReservation = res.rows.filter(object=>{
           return parseInt(object.starttime) >= nowTime;
         });
         console.log('nextReservation:',nextReservation);
         resolve(nextReservation);
       }else{
         resolve();
       }
     })
     .catch(e=>console.log(e));
 });
}

connection.query.then(res=>{ })の中に、

if(res.rows.length){
    ・・・・
}else{
    ・・・・
}

を追加しました。これは、データベースからデータを抜き出す命令に対し、予約データが返ってきたか、返ってこないかの判別をするためです。

プログラムのチェック

ここまで出来たらプログラムのチェックです。herokuへデプロイし、heroku logs --tailでログを立ち上げましょう。

スマホのLINEにて「予約キャンセル」をメッセージで送ります。

コンソールで「次回予約があります」や「次回予約なし」が表示されましたでしょうか。

heroku pg:psqlでデータベースを立ち上げ、DELETE文でデータ削除をしたりしながら色々試してみてください。

削除確認リプライの実装

ではhandleMessageEvent関数の中身を実装していきます。

こんなメッセージをリプライしたいです。Flex Message Simulatorでこんな確認メッセージを作成しましょう。

画像1

else if(text === '予約キャンセル'){
     const nextReservation = await checkNextReservation(ev);
     if(nextReservation.length){
       const startTimestamp = parseInt(nextReservation[0].starttime);
       const menu = MENU[parseInt(nextReservation[0].menu)];
       const date = dateConversion(startTimestamp);
       const id = parseInt(nextReservation[0].id);
       return client.replyMessage(ev.replyToken,{
         "type":"flex",
         "altText": "cancel message",
         "contents":
         {
           "type": "bubble",
           "body": {
             "type": "box",
             "layout": "vertical",
             "contents": [
               {
                 "type": "text",
                 "text": `次回の予約は${date}から、${menu}でおとりしてます。この予約をキャンセルしますか?`,
                 "size": "lg",
                 "wrap": true
               }
             ]
           },
           "footer": {
             "type": "box",
             "layout": "horizontal",
             "contents": [
               {
                 "type": "button",
                 "action": {
                   "type": "postback",
                   "label": "予約をキャンセルする",
                   "data": `delete&${id}`
                 }
               }
             ]
           }
         }
       });
     }else{
       return client.replyMessage(ev.replyToken,{
         "type":"text",
         "text":"次回予約は入っておりません。"
       });
     }
   }

まず初めに、checkNextReservation関数で次回の予約データを取得してます。「予約確認」イベントで使った関数をそのまま使い回し出来ますよね。

ボタンのイベント種別はpostbackです。そして、postbackのdataには`delete&${id}`としています。これは「予約をキャンセルする」ボタンがタップされた時に、deleteでイベントの振り分けをします。また、idは予約データをテーブルへインサートする際に、自動で割り振られたもので、データごとに唯一の値となっています。なので、予約データのidを渡してあげればどのデータを削除するのかを特定することが出来ます。

handlePostbackEvent関数内の実装

else if(splitData[0] === 'delete'){
     const id = parseInt(splitData[1]);
     const deleteQuery = {
       text:'DELETE FROM reservations WHERE id = $1;',
       values:[`${id}`]
     };
     connection.query(deleteQuery)
       .then(res=>{
         console.log('予約キャンセル成功');
         client.replyMessage(ev.replyToken,{
           "type":"text",
           "text":"予約をキャンセルしました。"
         });
       })
       .catch(e=>console.log(e));
   }

postback.dataは`delete&${id}`としましたので、split('&')で分割し、splitData[0]で処理の場合分け、そしてsplitData[1]に予約データのidが入っているので、それを整数型へパースします。

クエリ文はDELETE文で、テーブルからidが一致するものをテーブルから削除します。

削除したら予約キャンセルのメッセージをリプライします。

ここまで実装したら、デプロイし、確認してみましょう。

予約キャンセル

念の為、データテーブルから予約データが削除出来ているか確認してみましょう。

heroku pg:psql

でheroku postgresqlへ接続し、

DATABASE=> select * from reservations;

予約データが削除されているはずです。

さて、今回はここまでにしましょう。

次回はリッチメニューを作成してみたいと思います。

少しでも参考になりましたら、「スキ」をいただけると幸いです。

最後までお読みいただき、ありがとうございます。

MENTA でLINEBOT開発サポートをしております。お気軽にご相談ください。



この記事が気に入ったらサポートをしてみませんか?