feat: 增加真实采购任务安全模式 (#98)

This commit is contained in:
chengma
2026-08-10 15:11:38 +08:00
parent ba6710a2a2
commit 3aaa40cfe0
23 changed files with 642 additions and 66 deletions
+57
View File
@@ -3,6 +3,7 @@ package service
import (
"database/sql"
"errors"
"strings"
"testing"
"time"
@@ -369,6 +370,62 @@ func TestCreatePurchaseTasks_部分业务失败不影响有效明细(t *testing.
}
}
func TestCreatePurchaseTasksWithOptions_正常采购员可创建真实任务(t *testing.T) {
db := newTestDB(t)
key := seedPurchasableWorkflow(t, db, "SYB-LIVE")
SaveSybMapping(db, "SYB-LIVE", key, "USR-1")
admin, buyer, _ := prepareClientAssignmentUsers(t, db)
if err := RegisterClient(db, model.Client{ClientID: "CLIENT-LIVE", Capabilities: `{"purchase_mode":"live"}`}, true); err != nil {
t.Fatal(err)
}
if _, _, err := AssignClient(db, admin, "CLIENT-LIVE", buyer.UserID, time.Now()); err != nil {
t.Fatal(err)
}
result, err := CreatePurchaseTasksWithOptions(db, buyer,
[]PurchaseTaskRequest{{SybID: "SYB-LIVE", MaxPriceCent: 4200}},
PurchaseTaskOptions{ClientID: "CLIENT-LIVE", ExecutionMode: model.TaskExecutionLive,
LiveAcknowledged: true, LiveConfirmation: LivePurchaseConfirmation})
if err != nil || result.Created != 1 {
t.Fatalf("正常采购员创建真实任务失败: result=%+v err=%v", result, err)
}
var mode, confirmedBy string
var confirmedAt sql.NullString
if err := db.QueryRow(`SELECT execution_mode,live_confirmed_by,live_confirmed_at FROM tasks WHERE syb_id='SYB-LIVE'`).Scan(&mode, &confirmedBy, &confirmedAt); err != nil {
t.Fatal(err)
}
if mode != "live" || confirmedBy != buyer.UserID || !confirmedAt.Valid {
t.Fatalf("真实任务审计不完整: mode=%s by=%s at=%+v", mode, confirmedBy, confirmedAt)
}
}
func TestCreatePurchaseTasksWithOptions_真实模式安全门禁(t *testing.T) {
db := newTestDB(t)
key := seedPurchasableWorkflow(t, db, "SYB-GATE")
SaveSybMapping(db, "SYB-GATE", key, "USR-1")
admin, _, _ := prepareClientAssignmentUsers(t, db)
RegisterClient(db, model.Client{ClientID: "CLIENT-DRY", Capabilities: `{"purchase_mode":"dry_run"}`}, true)
request := []PurchaseTaskRequest{{SybID: "SYB-GATE", MaxPriceCent: 4200}}
if _, err := CreatePurchaseTasksWithOptions(db, admin, request, PurchaseTaskOptions{
ClientID: "CLIENT-DRY", ExecutionMode: model.TaskExecutionLive,
LiveAcknowledged: true, LiveConfirmation: LivePurchaseConfirmation,
}); err == nil || !strings.Contains(err.Error(), "未声明 live") {
t.Fatalf("dry_run 客户端必须被拒绝: %v", err)
}
if _, err := CreatePurchaseTasksWithOptions(db, admin, request, PurchaseTaskOptions{
ClientID: "CLIENT-DRY", ExecutionMode: model.TaskExecutionLive,
LiveAcknowledged: true, LiveConfirmation: "错误短语",
}); err == nil || !strings.Contains(err.Error(), "必须勾选") {
t.Fatalf("错误确认短语必须被拒绝: %v", err)
}
disabled := *admin
disabled.Status = model.UserDisabled
if _, err := CreatePurchaseTasks(db, &disabled, request, "CLIENT-DRY"); err == nil || !strings.Contains(err.Error(), "不是正常状态") {
t.Fatalf("禁用账号必须被拒绝: %v", err)
}
}
func TestParsePriceYuanToCent_精确转换(t *testing.T) {
for raw, want := range map[string]int64{"39.90": 3990, "1": 100, "0.01": 1, "12.3": 1230} {
got, err := ParsePriceYuanToCent(raw)