LoginSignup
41
26

More than 5 years have passed since last update.

社内のスマホ端末管理にTSUTAYAレジ風システムを導入した(予定)

Last updated at Posted at 2017-08-17

はじめに

この記事は1年近く前に投稿された「社内の備品貸出にTSUTAYAのレジ風システムを導入した」を ぱくって リスペクトして作ったシステムのお話です。
クライアントはAndroid(Kotlin)、サーバーはGASを使うことで短期間(2,3日くらい)で作成できた。

システム名は「たんまつ管理さん

(こらそこ、ダサいとか言わない)

なお、この記事投稿時点ではまだ運用してないです。

システムの構成図

system.001.jpeg

  • サーバー側の窓口をGASで実装。
  • GASがGoogleSpreadSheetと連携することで端末のデータを保存したり更新したりする
  • GASのスクリプト定期実行を利用して貸出期限切れがないかを定期的にチェック。期限切れがあれば即メールが飛ぶようになってる(組織によってはSlackとかでもいいかも)
  • サーバーを社内に置いていないのでスマホが社内ネットワークに繋がっていないと〜的なことが一切ない。LTEで繋がる。

スマホを識別する仕組み

まんまリスペクトした記事を参考にしました。

が!弊社のテプラが古いためQRコードを出力できず、PCのフリーサイトでQRコードを作成&印刷→テープでぺたりとかいうクソダサな対応になりそう。
新しいテプラを買ってくれないか交渉予定。
そんなわけでここは写真なしです。。

仕様的には、「<デバイス名>, <デバイス識別子>」といった形で、カンマ区切りで情報を並べる感じになってます。Galaxy Nexus 7(OS:5.1.1), 12みたいな感じ

会員カード(社員証でおk)

弊社の社員証の裏にはQRコードがプリントされており、そこには

  • 氏名
  • メールアドレス
  • 会社名
  • 社員番号

といった情報が書かれている。使わない手はない!ってことでこいつを利用。会員カード作る手間も、配布の手間もなくなって一石二鳥

クライアントアプリ

ソースはここ。ただしGASのURLはそれぞれ異なる関係上、修正する必要がある。詳しくはREADME.mdを参照。

最初の画面

login.png

ログイン画面

qr_login.png

メイン画面

main.png

借用、返却画面

rentaled.png

returned.png

端末一覧画面

list_rental.png

QRコード読みとりのあれこれ

QRコード読み取りにはzxingを使用、、したんですが、Android端末自体のフォーカス性能がiPhoneと比べ劣っているせいなのか、QRコードを読み込むのにどうしても時間がかかるのがストレス。
QRコード読み取りの実装自体はこちらの記事を参考にして実装。

端末一覧画面のあれこれ

参考にした「ネコレジ」にない機能としては、端末一覧の機能。この画面では全端末の状態が一覧できる。
レンタル可能なら白色背景、レンタル中は黄色、返却期限が過ぎているものは赤色になる。
一応申し訳程度の検索機能も用意はしてみたものの、And/Or検索できないというクソ仕様。端末数がめちゃ多くなったらいるのかなぁ〜・・・。

list_rental.png

Master/Slaveビルド

もう一つ「ネコレジ」にない機能として、Slaveビルドという設定をbuild.gradleで設けている。

build.gradle
    flavorDimensions "default"
    productFlavors {
        master {
            buildConfigField("jp.devicekanrisan.utils.commons.AppType", "APP_TYPE", "jp.devicekanrisan.utils.commons.AppType.MASTER")
            dimension "default"
        }
        slave {
            buildConfigField("jp.devicekanrisan.utils.commons.AppType", "APP_TYPE", "jp.devicekanrisan.utils.commons.AppType.SLAVE")
            dimension "default"
        }
    }

この設定が作用してるのは下のコード

LoginFragment.kt
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        if (BuildConfig.APP_TYPE == AppType.MASTER) {
            login_button.setOnClickListener {
                QRCodeReaderActivity.launch(context, navigateMessageId = R.string.navigate_message_login)
                activity.finish()
            }
        } else {
            login_button.visibility = View.GONE
        }
        list_button.setOnClickListener {
            DeviceListActivity.launch(context)
        }
    }

つまるところ、Slaveビルドだとこうなる

login_slave.png

Slaveビルドしたアプリは配布して端末状態を好きな時に確認できるように、Masterビルドしたアプリは端末置き場付近で貸出機として利用することができる。
Masterビルドしたものを配布してしまうと端末置き場に端末を返さなくても貸出、返却処理が行えてしまうという問題が出て来てしまうのでこのように対応。

通信APIはSwaggerで作成

過去に何回か記事でも取り上げたSwaggerでサクッとAPIを実装。残念ながらサーバー側(GAS)のgeneratorはないので今回はクライアント側のみの利用。それだけでも十分楽チン。
GASをサーバーとして使う場合、pathはexec/を指定しないといけないのが注意。というのもAndroid側(というよりはRetrofit2側)の仕様なのか、ルートパス指定だとアノテーションが@GET("") @POST("")みたいな感じで出力されてしまい、パスを認識してくれなかった。

今回作成したAPIはGistに公開してあるので参考に。

サーバー

GoogleActionScript

GASのいいところはサーバーレスでサーバーっぽいことが簡単に書けるところ。
詳しいサーバーの実装はGistに公開したのでこちらを参考に。
やってることはdoPostとdoGetでそれぞれJSONを受け取り、JSONでデータを返してるだけ。

またGASの特徴として定期実行も簡単に行える。それを利用して、1時間ごとに期限切れの人がいないかをチェックし、期限切れをしていたらメールを通知するようにしている。
具体的には以下の部分

main.gs
function timer() {
  checkReturnDate();
}

function checkReturnDate() {
  var now = new Date();
  var dataAll = getData();
  for( var i = 1; i < dataAll.length; i++) {
    var data = dataAll[i]
    if (data[Const.statusColumnIndex - 1] == "using" && now.getTime() > data[Const.returnDateColumnIndex - 1].getTime()) {
      sendNotify(data);
    }
  }
}

function sendNotify(data) {
  //通知を行う(mail)
  var address = data[Const.mailAddressColumnIndex - 1];
  var subject = "端末「" + data[Const.deviceNameColumnIndex - 1] + "」の返却期限が過ぎています!!";
  var body = "端末管理BOTからの連絡です\n\n" + data[Const.userNameColumnIndex - 1] 
  + "さんの借りている以下の端末は返却期限を過ぎています。可及的速やかに返却処理を行ってください\n【端末】\n"
  + data[Const.deviceNameColumnIndex - 1] + "\n\n\n※なお、この通知は返却しない限り1時間おきに実行されます";
  MailApp.sendEmail(address, subject, body)
}

function getData() {
  return data = getSheet().getDataRange().getValues();
}

/* シートを取得する */
function getSheet() {
  if (getSheet.instance) { return getSheet.instance; }
  var sheet = SpreadsheetApp.openById(Const.spreadSheetId).getSheetByName(Const.sheetName);
  return sheet;
}

ここではtimerメソッドを定期的に実行している。

41
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
26