予約サイトの設計

#施設、建物
```typescript
export interface Prop {
  //----------const
  id: number;
  na: string;
  roomTyps: number[];//洋室、和室、キャンプ、バンガロー等const ROOMTYPのid
  path: string;//ドメインnegura.gq
  lat: number;//googleMap
  lng: number;//googleMap
  zoom: number;//googleMap
  marker: number;//googleMap
  icon: string;
  users: string[];//編集権限のあるuserId
  txts: string[];//トップページのスライダーに表示
  //-----------MySQL
  price: number;//入場料
  charges: Charge[];//駐車料等他の料金
  close: boolean;//休止
  idx: number;//並び順
}
```
ドメイン名に一致するpathを持つpropがシステム単位になる。

###部屋タイプ
```typescript
export const ROOMTYP = {
  1: { na: '洋室' },
  2: { na: '和室' },
  3: { na: 'ドミトリー' },
  4: { na: 'バンガロー' },
  5: { na: 'キャンプ' }
}
```
変更することはほとんどないので定数としてconfigファイルにベタ書き
#部屋、区画
```typescript
export interface Room {
  id: number;
  prop: number;//建物、施設id
  typ: number;//ROOMTYP　和室、洋室、キャンプ、バンガローなど
  na: string;
  txt: string;//説明文
  img: string;
  simg: string;
  limg: string;
  price: number;//基本価格
  charges:Charge[];//追加人、車等への課金
  qty: number;//在庫、部屋数
  size: number;//フリーサイト面積上限
  created: Date;
  chat: boolean;//true=チャット口コミ書込み可
  close: boolean;//true=休止中
  idx: number;//並び順
  beds24: boolean;//true=OTA連携
  beds24id: number;//beds24のroomId
  max_people?: number;//↓beds24 params
  max_adult?: number;
  max_child?: number;
  min_stay?: number;
  max_stay?: number;
  min_price?: number;
}
```
基本となる貸出単位
###雑費
```typescript
export interface Charge {
  id: number;
  prop: number;
  room: number;
  key: string;
  typ: string;//people,vehicle,tent...etc
  min: number;
  max: number;
  price: number;
  idx: number;//並び順
}
```
人数追加料、こども料金、駐車料、テント代など
#予約料金算出クラス
```typescript
export class Unit {
  adult: number;
  child: number;
  vehicles: Vehicle[];
  constructor(adult?: number, child?: number, vehicles?: Vehicle[]) {
    this.adult = adult ? adult : 2;
    this.child = child ? child : 0;
    this.vehicles = vehicles ? vehicles : [{ id: 1, size: VEHICLETYP[1].size }];
  }
  protected toObj(array: any[]) {//[{id:x,...}]arrayからidでグループ化したcountを値に持つObject({x:count})を返す
    let data: any = {};
    for (let v of array) {
      if (data[v.id]) {
        data[v.id]++;
      } else {
        data[v.id] = 1;
      }
    }
    return data;
  }
  size(): number {
    let size = this.adult * 10 + this.child * 5;
    for (let vehicle of this.vehicles) {
      size += vehicle.size;
    }
    return size;
  }
  toString(): { people: string, vehicle: string } {
    let people = this.adult ? `大人:${this.adult}人　` : "";
    people += this.child ? `こども:${this.child}人　` : "";
    let vehicle = "";
    const obj = this.toObj(this.vehicles);
    Object.keys(obj).forEach(id => {
      vehicle += `${VEHICLETYP[id].na}:${obj[id]}台　`;
    })
    return { people: people, vehicle: vehicle };
  }
  price(room): number {
    let price = this.adult * room.price_adult + this.child * room.price_child;
    for (let vehicle of this.vehicles) {
      price += room[`price_${VEHICLETYP[vehicle.id].key}`];
    }
    return price;
  }
  queryParams(): Object {//ページ遷移時のクエリストリング生成用
    let params: any = {};
    if (this.adult) params.adult = this.adult;
    if (this.child) params.child = this.child;
    const obj = this.toObj(this.vehicles);
    Object.keys(obj).forEach(id => {
      params[VEHICLETYP[id].key] = obj[id];
    })
    return params;
  }
}
```
予約料金はroomオブジェクトをpriceメソッドに入れて算出する。
現在のpriceメソッドはChargeに対応していない。

昨日いただいたレビュー
「今後の拡張性を考慮すると、可変部分（課金対象は人？車？テント？、上限面積は？、等）は別クラスに分割しておいた方が、例えば別のキャンプ場に売る時などに、テストの範囲を限定できるかと思いました。」
を実現すべくChargeクラスを新設した。
######元のroomオブジェクト
```typescript
export interface Room {
  id: number;
  prop: number;//建物、施設id
  typ: number;//ROOMTYP　和室、洋室、キャンプ、バンガローなど
  na: string;
  txt: string;//説明文
  img: string;
  simg: string;
  limg: string;
  price: number;//標準価格
  qty: number;//在庫
  size: number;//フリーサイト面積上限
  created: Date;
  chat: boolean;//true=チャット口コミ書込み可
  close: boolean;//true=休止中
  idx: number;//並び順
  beds24: boolean;//true=OTA連携
  beds24id: number;//beds24のroomId
  max_people?: number;
  max_adult?: number;
  max_child?: number;
  min_stay?: number;
  max_stay?: number;
  min_price?: number;
  price_adult?: number;
  price_child?: number;
  price_car?: number;
  price_motorcycle?: number;
  price_bycycle?: number;
}
```
雑費をroomに直接並べていくのは拡張性を考えると避けるべきか？
###乗り物（雑費Charge.typのひとつ）
```typescript
export const VEHICLETYP = {
  0: { na: "", key: "", icon: "", size: 0 },
  1: { na: '車', key: "car", icon: "http://maps.google.co.jp/mapfiles/ms/icons/cabs.png", size: 10 },
  2: { na: 'バイク', key: "motorcycle", icon: "http://maps.google.co.jp/mapfiles/ms/icons/motorcycling.png", size: 5 },
  3: { na: '自転車', key: "bicycle", icon: "http://maps.google.co.jp/mapfiles/ms/icons/cycling.png", size: 3 },
  4: { na: 'トレーラー', key: "trailer", icon: "http://maps.google.co.jp/mapfiles/ms/icons/truck.png", size: 15 }
}
```
あまり変更することがないと思い定数にしたが、sizeは頻繁な変更が必要かも？
Vehicleを配列にした理由は、UIにsegment
https://ionicframework.com/jp/docs/api/segment
を使用したかったため。
利用者のほとんどは車１台、乗り物複数台は稀なので、乗り物の種類ごとに数を入力させるのではなく、乗り物の種類を選んでもらうというアプローチ。
![unitform.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1707372/3471c149-f80b-341a-3734-f6bf274adcf5.jpeg)
車２台は上のように表現され少々不自然だが、さらに最下部の＋ボタンでいくつでも追加できる。ほとんどの人にとっては今後乗り物の種類が増えてもUXが低下しない。
おかげでtoObj([])という余計なprotectedメソッドが必要になるが。

というわけで、これからUnitクラスのprice()メソッドをChargeオブジェクトに対応するよう改修していきます...