社内の備品貸出にTSUTAYAのレジ風システムを導入した

# 概要
社内の備品（主に`スマホ`や`パソコン`などの端末）をアプリで**「ピッ」**とスキャンするだけで、簡単に貸出/返却処理ができるTSUTAYAのレジ風システムを作りました。

**その名も「ネコレジ」**

OSSなテスト支援ツール**「[Chibineko](https://chibineko.jp)」**に続く、ねこシリーズ第2弾です。

# ネコレジのシステム構成
![ネコレジのシステム構成図](https://qiita-image-store.s3.amazonaws.com/0/43533/5463d32b-17a0-abfd-ddf7-51f447240446.png)


# 備品を識別する仕組み
備品の識別にはQRコードを使用します。
各備品にはそれぞれ一意のIDを埋め込んだQRコードを貼り、リーダー側（クライアントアプリ）で識別できるようにします。

![QRコードを貼った端末](https://qiita-image-store.s3.amazonaws.com/0/43533/5d50ce20-ad57-76a3-e5db-c0d95a65555c.jpeg)

QRコードの印刷には[**テプラPRO SR5900P**](http://www.kingjim.co.jp/products/tepra/detail/_id_SR5900P)を使用。
このテプラはLAN接続対応なので、iPhoneからも直接印刷ができるスグレモノです。

ちなみにうちの部署にはスマホやガラケーなどが1,000台以上ありますが、気合いですべてに貼りました。


# 会員カード（通称ネコカ）
ユーザーの識別も同様にQRコードで行います。
できるだけお金はかけたくないので手作り感満載で。

はがきサイズの厚紙に会員カードを印刷し、カッターでSuicaサイズに切り取ります。
続いて、カードの角がボロボロにならないよう専用のカッターで角を丸くし、耐久性を高めます。
仕上げにラミネートフィルムでコーティングして完成です。

**完成したネコカ**
![ネコカ](https://qiita-image-store.s3.amazonaws.com/0/43533/23d4a013-8612-c697-8e82-66878b8073fb.jpeg)

【使用した道具】

* [**ポストカードピュアWH**（etranger di costarica PC2-A-01）](http://www.amazon.co.jp/dp/B0013N7R4A/)
* [**かどまるPRO** （サンスター文具 S4765036）](http://www.amazon.co.jp/dp/B0076FJ7SS/)
* [**ラミネートフィルム 厚さ100ミクロン 名刺サイズ**（アイリスオーヤマ LZ-NC100）](http://www.amazon.co.jp/dp/B000O76S14/)

ちなみにカード1枚あたりの作成コストはわずか6円。
これなら気軽にバシバシ発行できますね。


# クライアントアプリ（QRコードリーダー）
上記で用意した**「QRコード付きの備品」**と**「会員カード」**を読み取るリーダーはiOSアプリ（Swift）で作りました。
ハンディタイプと据え置きタイプを想定して、iPhone/iPadのハイブリッド対応です。

![アプリ画面](https://qiita-image-store.s3.amazonaws.com/0/43533/f2f51574-113e-26a7-65a3-4ec4b0308617.png)

ちなみにQRコードリーダー部分のコードはこんな感じ。

`環境: Xcode7.3/Swift2.2/iOS8.3`

```swift
import UIKit
import AVFoundation

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let session = AVCaptureSession()
        let devices = AVCaptureDevice.devices()
        var device: AVCaptureDevice!
        let devicePosition = AVCaptureDevicePosition.Back  // 背面カメラを使用
        
        // カメラを取得
        for d in devices {
            if d.position == devicePosition {
                device = d as! AVCaptureDevice
                break
            }
        }
        
        // 取得したカメラをInputに設定
        do {
            let deviceInput = try AVCaptureDeviceInput(device: device)
            if session.canAddInput(deviceInput) {
                session.addInput(deviceInput)
            }
        } catch let error as NSError {
            print(error)
        }
        
        // OutputをQRコードに設定
        let metadataOutput = AVCaptureMetadataOutput()
        
        if session.canAddOutput(metadataOutput) {
            session.addOutput(metadataOutput)
            metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
            metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
        }
        
        // 読み取りエリアのViewを用意
        let videoLayer = AVCaptureVideoPreviewLayer(session: session)
        videoLayer.frame = self.view.bounds
        videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(videoLayer)
        
        session.startRunning()
    }
    
    // キャプチャ時に呼ばれるDelegate
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        if metadataObjects.count > 0 {
            let metaData = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
            print("\(metaData.type)")
            print("\(metaData.stringValue)")
        }
    }
}
```

Swiftでコードを書くのは今回が初めてでしたが、iOSにはデフォルトでQRコード読むためのライブラリが用意されているので実装自体はとても簡単でした。

またiPhoneのカメラはオートフォーカスの精度が高いので、QRコードの読み取り速度は驚くほど速く、アプリを使っていてとても気持ちが良いです。（[**こちらの動画**](https://youtu.be/zKMyp17Squ8)を参照）

ちなみに、QRコードの読み取り音はカスタマイズできるようにしたので、たとえば「マリオ - 敵を踏む音」にすれば、まとめて借りた時に連続でクリボーを踏んでるような気分になって楽しいです。

![ネコレジ_隠しモード](https://qiita-image-store.s3.amazonaws.com/0/43533/8b1cf2ec-cbf5-d7a8-44ce-61c638357e40.png)

注）この画面は秘密の操作を知っている人だけが入れる隠しモードです :sunglasses: 


# サーバー
ネコレジ導入前、備品の貸出管理はすべてWebベースの社内システムで行っていたのですが、毎日の貸出/返却の度にブラウザを起動して処理するのは正直手間でした。
そこで今回、この貸出管理システムのクライアントとなる「ネコレジ」を作ったわけですが、この既存システムとネコレジの連携は一筋縄ではいきませんでした。

というのも、アプリとWebサービスの連携は通常WebAPI（データをやり取りするインターフェース）を介して行うのですが、この貸出管理システムにはAPIが存在しないためそのままではアプリからのリクエストを受けることができません。
そこでネコレジでは、独自にAPIを実装することでこの問題を解決することにしました。

独自に実装と言っても方法は簡単で、WebページをスクレイピングしてJSON形式で返すサービスを作り、簡易的なAPIサーバーとするだけです。
詳細はまた機会があれば紹介したいと思いますが、自作の **「Bengal」** というライブラリを使用すると、取得したい情報のCSSセレクタを指定するだけで簡単にAPI(GET/POST)を実装することができます。

たとえば下記は `https://<APIサーバーのアドレス>/api/users/:id` にアクセスするとユーザー情報を返すAPIの例です。

```rb:app.rb
require 'bengal'

namespace '/api' do
  # ユーザー情報を取得するAPI
  get '/users/:id' do
    Bengal::Element.get(
      url: "https://example.com/users/#{params[:id]}",
      contents: [
        { name: "id", css: "#userid" },
        { name: "name", css: "#username" },
      ],
    ).to_json
  end
end
```

```json:APIの出力結果
{
  id: "25"
  name: "猫 太郎"
}
```

簡易的ではありますが、この方法を使えば既存のサービスのコードに一切手を入れることなくAPIが実装できるので便利です。


# おまけ
同僚が描いてくれたネコレジの使い方マニュアル。ゆるい。
![ネコレジ_2ステップ](https://qiita-image-store.s3.amazonaws.com/0/43533/f45adc47-64be-5459-d09a-d2437ac3953b.jpeg)


# 宣伝
世界で最もシンプルなテスト支援ツール**「Chibineko」**がOSSになりました。
https://github.com/tabbyz/chibineko

「[公式ホスティングサービス](https://chibineko.jp)」も無料なので是非ご活用ください。
タスク管理ツールとしても便利です。