管理端拆出宠物模块,并给它一个当班概览
值班的人打开控制台只想知道两件事:谁在等回复,钱还对不对得上。概览把 待裁定的申诉、待打款的提现、各类待审排在一屏,并把代管中、已结算、 平台服务费和账户余额一起摆出来;余额与流水对不上时先弹红条,因为那 种时候不该继续打款。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
46a60ffac3
commit
97351777ec
@@ -427,3 +427,81 @@ func seedAssignedTask(t *testing.T, a *App, db *sql.DB, owner, sitter int64) int
|
||||
}
|
||||
return taskID
|
||||
}
|
||||
|
||||
// The overview is what an operator opens first; if its numbers drift from the
|
||||
// lists behind them, they stop trusting the console and go back to SQL.
|
||||
func TestPetOverviewMySQL(t *testing.T) {
|
||||
db := isolatedIMDatabase(t)
|
||||
a := &App{db: db, hub: NewHub(), config: Config{Environment: "development", JWTSecret: "isolated-im-regression-secret-only"}}
|
||||
a.config.ConfigEncryptionKey = strings.Repeat("k", 32)
|
||||
owner, sitter := int64(1), int64(2)
|
||||
|
||||
read := func() map[string]any {
|
||||
t.Helper()
|
||||
var view map[string]any
|
||||
if err := json.Unmarshal(imTestCall(t, a.adminPetOverview, 1, "GET", "/admin/v1/pet/overview", "", 200), &view); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return view
|
||||
}
|
||||
number := func(view map[string]any, group, key string) int64 {
|
||||
t.Helper()
|
||||
section, ok := view[group].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("%s 不是一组数字: %+v", group, view[group])
|
||||
}
|
||||
return int64(section[key].(float64))
|
||||
}
|
||||
|
||||
empty := read()
|
||||
if number(empty, "pending", "disputes") != 0 || number(empty, "money", "escrowedCent") != 0 {
|
||||
t.Fatalf("空库时待办与代管金额应当都是 0: %+v", empty)
|
||||
}
|
||||
|
||||
taskID := seedAssignedTask(t, a, db, owner, sitter)
|
||||
// seedAssignedTask 停在"待确认":钱已经收了,还没结算给任何人。
|
||||
held := read()
|
||||
if number(held, "money", "escrowedCent") != 9000 {
|
||||
t.Fatalf("代管金额 = %d,应当是 3 次 30 元", number(held, "money", "escrowedCent"))
|
||||
}
|
||||
if number(held, "tasks", "COMPLETED") != 1 {
|
||||
t.Fatalf("待确认任务数不对: %+v", held["tasks"])
|
||||
}
|
||||
|
||||
raise := httptest.NewRecorder()
|
||||
a.raiseFeedDispute(raise, imTestRequest(owner, "POST", fmt.Sprintf("/api/v1/pet/feed-tasks/%d/dispute", taskID),
|
||||
`{"reason":"照片对不上,猫粮碗一直是满的,怀疑没有真的上门"}`))
|
||||
if raise.Code != 200 {
|
||||
t.Fatalf("HTTP %d: %s", raise.Code, raise.Body.String())
|
||||
}
|
||||
disputed := read()
|
||||
if number(disputed, "pending", "disputes") != 1 {
|
||||
t.Fatalf("待处理申诉应当是 1: %+v", disputed["pending"])
|
||||
}
|
||||
// 申诉中的任务仍算代管:钱既没退也没结。
|
||||
if number(disputed, "money", "escrowedCent") != 9000 {
|
||||
t.Fatalf("申诉期间代管金额不该消失: %d", number(disputed, "money", "escrowedCent"))
|
||||
}
|
||||
|
||||
var disputeID int64
|
||||
if err := db.QueryRow(`SELECT id FROM pet_feed_disputes WHERE task_id=?`, taskID).Scan(&disputeID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handle := httptest.NewRecorder()
|
||||
a.adminHandleFeedDispute(handle, imTestRequest(1, "POST", fmt.Sprintf("/admin/v1/pet/disputes/%d/handle", disputeID),
|
||||
`{"verdict":"payout","note":"照片与定位都对得上,判全额支付"}`))
|
||||
if handle.Code != 200 {
|
||||
t.Fatalf("HTTP %d: %s", handle.Code, handle.Body.String())
|
||||
}
|
||||
settled := read()
|
||||
if number(settled, "pending", "disputes") != 0 || number(settled, "money", "escrowedCent") != 0 {
|
||||
t.Fatalf("裁定之后待办与代管都应当归零: %+v", settled)
|
||||
}
|
||||
if number(settled, "money", "walletBalanceCent") != number(settled, "money", "settledCent") {
|
||||
t.Fatalf("已结算金额与账户余额应当一致: %+v", settled["money"])
|
||||
}
|
||||
// 账实一致是继续打款的前提,概览要能自己回答这件事。
|
||||
if settled["ledgerMismatches"].(float64) != 0 {
|
||||
t.Fatalf("对账出现差异: %+v", settled)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user