マーケットプレイス v1

店ごとに売上金を持つ。売上は、買い手が払った額を店の売上金と手数料に分ける(額は呼ぶ側が計算して渡す。手数料は規則が決める)。振込は銀行が受け付けるまで押さえ、返金は両方を戻す

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

勘定

勘定分け方単位境界説明
売上金店 ごと円0 以上。下回る振替は 売上金不足 で拒否されるマーケットプレイスが店に払う分
買い手一つだけ円外の勘定。境界は無く、マイナスにもなる
手数料収入一つだけ円外の勘定。境界は無く、マイナスにもなる
銀行一つだけ円外の勘定。境界は無く、マイナスにもなる

勘定のあいだの流れ

マーケットプレイス の勘定のあいだの流れ 売上(店の取り分) 売上(手数料) 返金(手数料) 返金(店の取り分) 振込 売上金(店)円0 以上(売上金不足) 買い手円・外の勘定 手数料収入円・外の勘定 銀行円・外の勘定

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

振替

売上

店の取り分と手数料を足すと、買い手が払った額になる。手数料は呼ぶ側が計算する

  • 移動は 2 つ。書いた順に行い、どれか一つでも拒否されたら、どれも行わない:
    1. 買い手 から 売上金(店) へ 店の取り分
    2. 買い手 から 手数料収入 へ 手数料
  • キー: 注文 ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、done_before を返す。キーが同じで 店、店の取り分、手数料 のどれかが違う二度目の呼び出しは、key_conflict で拒否される。
  • すぐに動かす(do)。
操作拒否されうる理由いつ
売上.dokey_conflict注文 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
拒否される例

売上.do: key_conflict

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 1, 手数料: 2)  通る
 2  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 3, 手数料: 2)  key_conflict で拒否される

返金

手数料と店の取り分を、両方とも戻すか、どちらも戻さない

  • 移動は 2 つ。書いた順に行い、どれか一つでも拒否されたら、どれも行わない:
    1. 手数料収入 から 買い手 へ 手数料
    2. 売上金(店) から 買い手 へ 店の取り分
  • キー: 返金番号 ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、done_before を返す。キーが同じで 店、店の取り分、手数料 のどれかが違う二度目の呼び出しは、key_conflict で拒否される。
  • すぐに動かす(do)。
操作拒否されうる理由いつ
返金.do売上金不足2 つ目の移動で 売上金(店) が 0 を下回る
返金.dokey_conflict返金番号 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
返金.doalready_refused返金番号 が同じ呼び出しが、前に境界で拒否されている。境界で拒否されたキーは、あとで足りるようになっても通らない
拒否される例

返金.do: 売上金不足

 1  返金.do(返金番号: 返金番号-1, 店: 店-2, 店の取り分: 1, 手数料: 2)  売上金不足 で拒否される(2 つ目の移動が 売上金(店-2) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)

返金.do: key_conflict

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 1, 手数料: 3)          通る
 2  返金.do(返金番号: 返金番号-3, 店: 店-2, 店の取り分: 1, 手数料: 2)  通る
 3  返金.do(返金番号: 返金番号-3, 店: 店-2, 店の取り分: 4, 手数料: 2)  key_conflict で拒否される

返金.do: already_refused

 1  返金.do(返金番号: 返金番号-1, 店: 店-2, 店の取り分: 1, 手数料: 2)  売上金不足 で拒否される(2 つ目の移動が 売上金(店-2) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)
 2  返金.do(返金番号: 返金番号-1, 店: 店-2, 店の取り分: 1, 手数料: 2)  already_refused で拒否される

振込

銀行振込を始めたときに押さえる。銀行が受け付けたら確定し、失敗したら取り消す

  • 移動: 売上金(店) から 銀行 へ 額。
  • キー: 振込番号 ごとに一度だけ動く。同じ呼び出しの二度目は何もせず、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売上金不足売上金(店) が 0 を下回る
振込.holdkey_conflict振込番号 が同じで、ほかの引数が違う呼び出しが、前に済んでいる
振込.holdalready_refused振込番号 が同じ呼び出しが、前に境界で拒否されている。境界で拒否されたキーは、あとで足りるようになっても通らない
振込.postkey_conflict仮押さえは、違う額で確定済み
振込.postalready_voided仮押さえはもう取り消されている
振込.postover_hold押さえた額より多く確定しようとした
振込.postno_such_holdその 振込番号 の仮押さえが無い
振込.voidalready_posted仮押さえはもう確定している
振込.voidno_such_holdその 振込番号 の仮押さえが無い
拒否される例

振込.hold: 売上金不足

 1  振込.hold(振込番号: 振込番号-1, 店: 店-2, 額: 1)  売上金不足 で拒否される(1 つ目の移動が 売上金(店-2) から 1 を取ろうとしたときの残高は、確定 0、出ていく仮押さえ 0)

振込.hold: key_conflict

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 1, 手数料: 2)  通る
 2  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 1)           通る
 3  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 3)           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  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 2, 手数料: 3)  通る
 2  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 2)           通る
 3  振込.post(振込番号: 振込番号-3)                            通る
 4  振込.post(振込番号: 振込番号-3, 額: 1)                     key_conflict で拒否される

振込.post: already_voided

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 2, 手数料: 3)  通る
 2  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 2)           通る
 3  振込.void(振込番号: 振込番号-3)                            通る
 4  振込.post(振込番号: 振込番号-3)                            already_voided で拒否される

振込.post: over_hold

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 2, 手数料: 3)  通る
 2  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 2)           通る
 3  振込.post(振込番号: 振込番号-3, 額: 3)                     over_hold で拒否される

振込.post: no_such_hold

 1  振込.post(振込番号: 振込番号-1)  no_such_hold で拒否される

振込.void: already_posted

 1  売上.do(注文: 注文-1, 店: 店-2, 店の取り分: 2, 手数料: 3)  通る
 2  振込.hold(振込番号: 振込番号-3, 店: 店-2, 額: 2)           通る
 3  振込.post(振込番号: 振込番号-3)                            通る
 4  振込.void(振込番号: 振込番号-3)                            already_posted で拒否される

振込.void: no_such_hold

 1  振込.void(振込番号: 振込番号-1)  no_such_hold で拒否される

シナリオ

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

    勘定確定出ていく仮押さえ入ってくる仮押さえ
    仮押さえ状態
    マーケットプレイス の勘定のあいだの流れ 売上(店の取り分) 売上(手数料) 返金(手数料) 返金(店の取り分) 振込 売上金(店)円0 以上(売上金不足) 買い手円・外の勘定 手数料収入円・外の勘定 銀行円・外の勘定