Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Subscriptionsについて

about_subscriptions.livemd

Subscriptionsについて

alias Bright.Accounts
alias Bright.Subscriptions

Brightにおける有料サービスの概念

有料サービスに関する概念については概念ER図を参照

Subscriptionsコンテキストのデータモデル

SubscriptionsコンテキストはBrightにおける定額契約プランおよびプラン事に利用可能となる機能群(Service)から構成される。

erDiagram
  "SubscriptionPlan"||--|{"SubscriptionPlanService" : "利用可能なサービス群"
  "SubscriptionPlan"||--o{"SubscriptionUserPlan" : ""
  "SubscriptionUserPlan"}o--o{"User" : "契約したプラン(過去分を含む)"

以下、subscription_planssubscription_user_plansのカラムである。

erDiagram

  subscription_plans {
    string plan_code "プランを表すコード 一意"
    string name_jp "プラン表示名"
    integer free_trial_priority "無料トライアルの優先度 小さい方が優先 nilは対象外"
    integer authorization_priority "プランの採用優先度 大きい方が優先 上位プランが大"
    integer create_teams_limit "通常チームの作成数上限"
    integer team_members_limit "チームのメンバー数上限"
    integer create_enable_hr_functions_teams_limit "育成・支援チームの作成数上限"
    datetime available_contract_end_datetime "契約そのものの終了日時"
  }
  • 特にauthorization_priorityは重ならないように設定する。
erDiagram

  subscription_user_plans {
    id user_id FK
    id subscription_plan FK
    string subscription_status "enum(free_trial: 無料トライアル中, subscribing: 契約中, subscription_ended: 契約終了)"
    datetime subscription_start_datetime "契約の開始日時"
    datetime subscription_end_datetime "契約の終了日時 (未完了の場合はnil)"
    datetime trial_start_datetime "無料トライアルの開始日時 (トライアル未利用の場合はnil)"
    datetime trial_end_datetime "無料トライアルの終了日時 (トライアル未利用または未完了の場合はnil)"
  }
  • 過去の契約履歴を含むため複数のsubscription_user_plansレコードが存在しうる。
  • 通常1ユーザーには複数のsubscription_status: subscribingなレコードは存在しない。
    • 上位プランが下位プランの機能(権限及び制限)を包含する。
    • ただし、システム上は発生を想定して上位プランを優先して適用する。
  • 一方で、トライアル中に、subscription_status: subscribingとfree_trialのレコードは同時に存在する。
    • この場合は、上位プランを優先して適用する。
  • subscription_start_datetimeに値があり、subscription_end_datetimeに値がない場合に「契約中」である。
    • subscription_start_datetimeが未来日時のときはその日時より契約中となる。
    • subscription_end_datetimeが未来日時であっても値があれば契約完了として扱われる。
  • trial_start_datetimeに値があり、trial_end_datetimeに値がない場合に「トライアル中」である。
    • trial_start_datetimeが未来日時のときはその日時よりトライアル中となる。
    • trial_end_datetimeが未来日時であっても値があればトライアル完了として扱われる。

プラン・サービス・機能の要件

Brightのサービス・機能と利用可能なプランのマッピングについてはサービス/機能/課金プラン/権限チェック(個人、チーム)を参照

表中のサービス分類と対応する初期データのservice_codeは下表参照

サービス分類 service_code
スキルアップ skill_up
チームアップ team_up
採用・育成共通 hr_basic
採用 hr_recruitment
育成 hr_training

拡張プランについて

チーム数制限などを一般的なプランよりも大きく設定するプランを作る際には下記に注意する。

  • plan_codeをそれとわかるようにすること
    • hr_planであればhr_plan_extended_のような命名とする
  • authorization_priorityを同じ機能を使えるプランよりも大きく、上位プランよりも小さくすること
  • free_trial_priorityを設定しないこと
    • 無料トライアル対象外にするため

無料トライアルで利用可能なプラン

ユーザーはプランの無料トライアルを利用できる。ただし、利用可能かどうかはユーザー状況やプランで条件がある。

  • 個者(社)対応として作成されているプランは利用できない。
    • データ上は、subscription_plans.free_trial_priorityがnilなデータが該当する。
  • 同一プランで、既にトライアル中か契約中がある(完了含む)場合は利用できない。
    • 同一とは、データ上ではsubscription_plans.plan_codeを指す。
    • 上位プランのトライアルや契約が完了している場合は、利用できる。あくまで同一かどうかをみる。
  • より上位のプランのトライアル中か契約中であれば、利用できない。
    • まず画面上において誘導しない。データ上は問題としない。
    • 逆に、下位プランの無料トライアル中か契約中のときは利用できる。
  • 個者(社)対応として作成されているプランは利用できない。
    • データ上は、subscription_plans.free_trial_priorityがnilなデータが該当する。

サブスクリプションプランとサービスの初期データ登録

priv/repo/seed_dummy_data.exsに収録すみの下記関数でサービスタリフに即した初期データを登録できる。 収録データについてはSeedsファイル参照

Bright.Seeds.SubscriptionPlan.delete()
Bright.Seeds.SubscriptionPlan.insert()
Bright.Seeds.SubscriptionPlanService.insert()

Bright.Seeds.SubscriptionPlan.delete()は、ユーザー毎の契約履歴も削除するので注意すること。

Subscriptions関数

前提情報の取得

# ユーザーID
Accounts.get_user_by_name_or_email("takuto4devops@gmail.com")
# プラン情報
Subscriptions.get_subscription_plan_with_enable_services_by_plan_code("team_up_plan")

登録系

※ 現状用意している関数では契約の重複チェックなど業務よりのバリデーションは未実装

# 無料トライアルの開始
Subscriptions.start_free_trial(user_id, subscription_plan_id)
# 即時有料プランの開始
Subscriptions.start_subscription(user_id, subscription_plan_id)

判定系

# サービスコードをキーに該当サービスの利用有無を返す
Subscriptions.service_enabled?(user_id, service_code)
# サービスコードをキーに該当サービスが利用可能な最も優先度の高いサブスクリプションプランを返す
Subscriptions.get_most_priority_free_trial_subscription_plan(service_code)

# 現在契約中のプランがあれば指定が必要
Subscriptions.get_most_priority_free_trial_subscription_plan(service_code, current_plan)

# サービスではなく、チーム数やチームメンバー数の上限で探す場合は下記
Subscriptions.get_most_priority_free_trial_subscription_plan_by_teams_limit(create_teams_limit, current_plan)
Subscriptions.get_most_priority_free_trial_subscription_plan_by_members_limit(team_members_limit, current_plan)
# プランコードをキーに該当プランのフリートライアル利用可否を返す
#  ある場合、利用不可
Subscriptions.free_trial_available?(user_id, plan_code)

取得系

# ユーザーIDと基準時刻をキーに有効な契約内容を取得する
Subscriptions.get_users_subscription_status(user_id, NaiveDateTime.utc_now())
# ユーザーIDから現在有効な最上位のプラン(トライアル/契約を問わない)を取得する
Subscriptions.get_user_subscription_user_plan(user_id)
# フリートライアル済のプラン一覧を返す
Subscriptions.get_users_trialed_plans(user_id)