ポイント v1

会員ごとのポイント。購入で付く分は返品の期間が過ぎるまで押さえ、会計で使う分は支払いが通るまで 15 分押さえる。期間の終わりに使われずに残った分は失効する

chobo doc が examples/points/points.ja.book から作ったページ。勘定ごとに残高を持ち、残高は入った量から出た量を引いたもの。どの振替も勘定の下限と上限を守り、守れない振替は、その境界に付けた名前で拒否されて、どの移動も行われない。振替には、すぐに動かすもの(do)と、動かす量をまず押さえるもの(hold)がある。押さえた分は、あとで確定される(post。全部か一部)か、取り消される(void)か、有効期限で切れる。

勘定

勘定分け方単位境界説明
ポイント会員 ごとpt0 以上。下回る振替は ポイント不足 で拒否される
1000000 以下。超える振替は 上限超え で拒否される
発行一つだけpt外の勘定。境界は無く、マイナスにもなる
利用済み一つだけpt外の勘定。境界は無く、マイナスにもなる
失効済み一つだけpt外の勘定。境界は無く、マイナスにもなる

勘定のあいだの流れ

ポイント の勘定のあいだの流れ 付与 利用 失効 ポイント(会員)pt0 以上(ポイント不足)1000000 以下(上限超え) 発行pt・外の勘定 利用済みpt・外の勘定 失効済みpt・外の勘定

四角は勘定で、矢印は振替の移動。角の丸い破線の四角は外の勘定で、境界を持たない。破線の矢印は仮押さえの振替で、まず押さえ、確定したときに動く。

振替

付与

返品の期間が過ぎたら確定し、返品されたら取り消す

  • 移動: 発行 から ポイント(会員) へ 数。
  • キー: 購入 ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、done_before を返す。キーが同じで 会員、数 のどれかが違う二度目の呼び出しは、key_conflict で拒否される。仮押さえが終わったあとに同じキーでもう一度押さえると、done_before を返し、何も押さえない。
  • 仮押さえ: まず押さえる。確定と取消は呼ぶ側がする。期限は無く、どちらかが来るまで押さえたまま。
付与.hold 押さえ中 確定(post) 確定 取消は already_posted で拒否される 違う額の確定は key_conflict で拒否される 取消(void) 取消 確定は already_voided で拒否される
仮押さえの状態post(確定)void(取消)
押さえ中確定する。額を渡せばその額、渡さなければ全額で、残りは元に戻る。押さえた額を超えれば over_hold で拒否される取り消す。押さえた量は元に戻る
確定同じ額なら done_before、違う額なら key_conflict で拒否されるalready_posted で拒否される
取消already_voided で拒否されるdone_before
仮押さえが無いno_such_hold で拒否されるno_such_hold で拒否される
操作拒否されうる理由いつ
付与.hold上限超えポイント(会員) が 1000000 を超える
付与.holdkey_conflict購入 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
付与.holdalready_refused購入 が同じ呼び出しが、前に境界で拒否されている。境界で拒否されたキーは、あとで足りるようになっても通らない
付与.postkey_conflict仮押さえは、違う額で確定済み
付与.postalready_voided仮押さえはもう取り消されている
付与.postover_hold押さえた額より多く確定しようとした
付与.postno_such_holdその 購入 の仮押さえが無い
付与.voidalready_posted仮押さえはもう確定している
付与.voidno_such_holdその 購入 の仮押さえが無い
拒否される例

付与.hold: 上限超え

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 1000000)  通る
 2  付与.post(購入: 購入-1)                             通る
 3  付与.hold(購入: 購入-3, 会員: 会員-2, 数: 1)        上限超え で拒否される(1 つ目の移動が ポイント(会員-2) へ 1 を入れようとしたときの残高は、確定 1000000、入ってくる仮押さえ 0)

付与.hold: key_conflict

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 1)  通る
 2  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  key_conflict で拒否される

付与.hold: already_refused

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 1000000)  通る
 2  付与.post(購入: 購入-1)                             通る
 3  付与.hold(購入: 購入-3, 会員: 会員-2, 数: 1)        上限超え で拒否される(1 つ目の移動が ポイント(会員-2) へ 1 を入れようとしたときの残高は、確定 1000000、入ってくる仮押さえ 0)
 4  付与.hold(購入: 購入-3, 会員: 会員-2, 数: 1)        already_refused で拒否される

付与.post: key_conflict

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  付与.post(購入: 購入-1, 数: 1)                key_conflict で拒否される

付与.post: already_voided

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.void(購入: 購入-1)                       通る
 3  付与.post(購入: 購入-1)                       already_voided で拒否される

付与.post: over_hold

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1, 数: 3)                over_hold で拒否される

付与.post: no_such_hold

 1  付与.post(購入: 購入-1)  no_such_hold で拒否される

付与.void: already_posted

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  付与.void(購入: 購入-1)                       already_posted で拒否される

付与.void: no_such_hold

 1  付与.void(購入: 購入-1)  no_such_hold で拒否される

利用

支払いが通ったら確定し、通らなかったら取り消す

  • 移動: ポイント(会員) から 利用済み へ 数。
  • キー: 会計 ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、done_before を返す。キーが同じで 会員、数 のどれかが違う二度目の呼び出しは、key_conflict で拒否される。仮押さえが終わったあとに同じキーでもう一度押さえると、done_before を返し、何も押さえない。
  • 仮押さえ: まず押さえる。確定と取消は呼ぶ側がする。押さえてから 15 分で期限が切れ、押さえた量は元に戻る。
利用.hold 押さえ中 確定(post) 確定 取消は already_posted で拒否される 違う額の確定は key_conflict で拒否される 取消(void) 取消 確定は already_voided で拒否される 15 分たつ 期限切れ 確定も取消も expired で拒否される
仮押さえの状態post(確定)void(取消)
押さえ中確定する。額を渡せばその額、渡さなければ全額で、残りは元に戻る。押さえた額を超えれば over_hold で拒否される。押さえてから 15 分たっていれば expired で拒否される取り消す。押さえた量は元に戻る。押さえてから 15 分たっていれば expired で拒否される
確定同じ額なら done_before、違う額なら key_conflict で拒否されるalready_posted で拒否される
取消already_voided で拒否されるdone_before
期限切れexpired で拒否されるexpired で拒否される
仮押さえが無いno_such_hold で拒否されるno_such_hold で拒否される
操作拒否されうる理由いつ
利用.holdポイント不足ポイント(会員) が 0 を下回る
利用.holdkey_conflict会計 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
利用.holdalready_refused会計 が同じ呼び出しが、前に境界で拒否されている。境界で拒否されたキーは、あとで足りるようになっても通らない
利用.postkey_conflict仮押さえは、違う額で確定済み
利用.postalready_voided仮押さえはもう取り消されている
利用.postexpired仮押さえの期限が切れている
利用.postover_hold押さえた額より多く確定しようとした
利用.postno_such_holdその 会計 の仮押さえが無い
利用.voidalready_posted仮押さえはもう確定している
利用.voidexpired仮押さえの期限が切れている
利用.voidno_such_holdその 会計 の仮押さえが無い
拒否される例

利用.hold: ポイント不足

 1  利用.hold(会計: 会計-1, 会員: 会員-2, 数: 1)  ポイント不足 で拒否される(1 つ目の移動が ポイント(会員-2) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)

利用.hold: key_conflict

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 1)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 1)  通る
 4  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  key_conflict で拒否される

利用.hold: already_refused

 1  利用.hold(会計: 会計-1, 会員: 会員-2, 数: 1)  ポイント不足 で拒否される(1 つ目の移動が ポイント(会員-2) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)
 2  利用.hold(会計: 会計-1, 会員: 会員-2, 数: 1)  already_refused で拒否される

利用.post: key_conflict

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  利用.post(会計: 会計-3)                       通る
 5  利用.post(会計: 会計-3, 数: 1)                key_conflict で拒否される

利用.post: already_voided

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  利用.void(会計: 会計-3)                       通る
 5  利用.post(会計: 会計-3)                       already_voided で拒否される

利用.post: expired

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  pass 15 分                                    利用(会計-3) が期限切れ
 5  利用.post(会計: 会計-3)                       expired で拒否される

利用.post: over_hold

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  利用.post(会計: 会計-3, 数: 3)                over_hold で拒否される

利用.post: no_such_hold

 1  利用.post(会計: 会計-1)  no_such_hold で拒否される

利用.void: already_posted

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  利用.post(会計: 会計-3)                       通る
 5  利用.void(会計: 会計-3)                       already_posted で拒否される

利用.void: expired

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 2)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  利用.hold(会計: 会計-3, 会員: 会員-2, 数: 2)  通る
 4  pass 15 分                                    利用(会計-3) が期限切れ
 5  利用.void(会計: 会計-3)                       expired で拒否される

利用.void: no_such_hold

 1  利用.void(会計: 会計-1)  no_such_hold で拒否される

失効

その期間に使われなかった分

  • 移動: ポイント(会員) から 失効済み へ 数。
  • キー: 会員 と 期間 の組ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、done_before を返す。キーが同じで 数 が違う二度目の呼び出しは、key_conflict で拒否される。
  • すぐに動かす(do)。
操作拒否されうる理由いつ
失効.doポイント不足ポイント(会員) が 0 を下回る
失効.dokey_conflict会員 と 期間 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
失効.doalready_refused会員 と 期間 が同じ呼び出しが、前に境界で拒否されている。境界で拒否されたキーは、あとで足りるようになっても通らない
拒否される例

失効.do: ポイント不足

 1  失効.do(会員: 会員-1, 期間: 期間-2, 数: 1)  ポイント不足 で拒否される(1 つ目の移動が ポイント(会員-1) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)

失効.do: key_conflict

 1  付与.hold(購入: 購入-1, 会員: 会員-2, 数: 1)  通る
 2  付与.post(購入: 購入-1)                       通る
 3  失効.do(会員: 会員-2, 期間: 期間-3, 数: 1)    通る
 4  失効.do(会員: 会員-2, 期間: 期間-3, 数: 2)    key_conflict で拒否される

失効.do: already_refused

 1  失効.do(会員: 会員-1, 期間: 期間-2, 数: 1)  ポイント不足 で拒否される(1 つ目の移動が ポイント(会員-1) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)
 2  失効.do(会員: 会員-1, 期間: 期間-2, 数: 1)  already_refused で拒否される

シナリオ

chobo scenarios が帳簿から作ったシナリオ 39 本。一つ選び、ステップを一つずつ進めると、そのあとの残高と仮押さえが見られる。図では、そのステップで呼んだ振替の矢印に色が付く(拒否されたものは赤)。

    勘定確定出ていく仮押さえ入ってくる仮押さえ
    仮押さえ状態
    ポイント の勘定のあいだの流れ 付与 利用 失効 ポイント(会員)pt0 以上(ポイント不足)1000000 以下(上限超え) 発行pt・外の勘定 利用済みpt・外の勘定 失効済みpt・外の勘定