feat: 采购详情展示 PDD 核单结果 (#125)
This commit is contained in:
@@ -84,6 +84,22 @@ func TestPddDetailRecollect_使用独立入口并可选客户端(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaskDetail_采购核单结果使用独立只读分组(t *testing.T) {
|
||||
content, err := os.ReadFile("templates/task/detail_modal.html")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
page := string(content)
|
||||
for _, want := range []string{
|
||||
"PDD 核单结果", "PDD 订单编号", "下单时间", "上报时付款状态",
|
||||
"{{if .IsPurchase}}", "{{if .HasPddOrder}}", "完整结果(result_data)",
|
||||
} {
|
||||
if !strings.Contains(page, want) {
|
||||
t.Errorf("采购任务详情缺少 %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatesAndRoutesCanBeBuiltWithoutDatabaseConnection(t *testing.T) {
|
||||
if _, err := newRouter(nil); err != nil {
|
||||
t.Fatalf("模板或路由组装失败: %v", err)
|
||||
|
||||
@@ -345,6 +345,14 @@ type TaskDetailView struct {
|
||||
QuantityText string
|
||||
PriceLimitText string
|
||||
|
||||
// PDD 核单结果只在采购任务详情显示。付款状态是 Client 核单上报时的快照,
|
||||
// 不是 Admin 对 PDD 的实时查询结果。
|
||||
HasPddOrder bool
|
||||
PddOrderNo string
|
||||
PddOrderedAt string
|
||||
PddPaymentStatusText string
|
||||
PddOrderResultText string
|
||||
|
||||
HasError bool
|
||||
ErrorCode string
|
||||
ErrorMessage string
|
||||
@@ -377,6 +385,7 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
|
||||
v.SpecText = specText(t.PddOptions)
|
||||
v.QuantityText = quantityText(t.Quantity)
|
||||
v.PriceLimitText = priceLimitText(t.MaxPriceCent)
|
||||
setPddOrderResult(v, *t)
|
||||
}
|
||||
|
||||
if t.ErrorCode != "" || t.ErrorMessage != "" {
|
||||
@@ -392,6 +401,61 @@ func GetTaskDetail(db *sql.DB, taskID string) (*TaskDetailView, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// purchaseResult 只声明详情页需要展示的字段,避免把 Client 的完整结果结构
|
||||
// 复制到 Admin。其余原始字段仍保存在 result_data 并可在详情底部展开查看。
|
||||
type purchaseResult struct {
|
||||
Purchase *struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
OrderedAt string `json:"ordered_at"`
|
||||
PaymentStatus string `json:"payment_status"`
|
||||
MatchStatus string `json:"match_status"`
|
||||
OrderSubmitted bool `json:"order_submitted"`
|
||||
} `json:"purchase"`
|
||||
}
|
||||
|
||||
// setPddOrderResult 把采购结果翻成模板可直接显示的文字。
|
||||
// 解析失败只影响结构化摘要,不能阻止详情页打开,也不能隐藏原始 result_data。
|
||||
func setPddOrderResult(v *TaskDetailView, task model.Task) {
|
||||
raw := strings.TrimSpace(task.ResultData)
|
||||
if raw == "" {
|
||||
switch task.Status {
|
||||
case model.TaskManualReview:
|
||||
v.PddOrderResultText = "订单结果不确定,请结合错误信息人工核对。"
|
||||
case model.TaskFailed, model.TaskCancelled:
|
||||
v.PddOrderResultText = "任务未产生可展示的 PDD 核单结果。"
|
||||
default:
|
||||
v.PddOrderResultText = "等待 Client 核单上报。"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var result purchaseResult
|
||||
if err := json.Unmarshal([]byte(raw), &result); err != nil || result.Purchase == nil {
|
||||
v.PddOrderResultText = "采购结果格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
p := result.Purchase
|
||||
if p.MatchStatus != "matched" || !p.OrderSubmitted {
|
||||
v.PddOrderResultText = "本次结果没有已匹配的 PDD 订单。"
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(p.OrderNo) == "" || p.PaymentStatus != "unpaid" {
|
||||
v.PddOrderResultText = "采购结果格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
orderedAt, ok := model.ParseISO(strings.TrimSpace(p.OrderedAt))
|
||||
if !ok {
|
||||
v.PddOrderResultText = "采购结果中的下单时间格式异常,请展开完整结果进行诊断。"
|
||||
return
|
||||
}
|
||||
|
||||
v.HasPddOrder = true
|
||||
v.PddOrderNo = strings.TrimSpace(p.OrderNo)
|
||||
v.PddOrderedAt = orderedAt.Local().Format("2006-01-02 15:04")
|
||||
v.PddPaymentStatusText = "未付款(Client 上报时)"
|
||||
v.PddOrderResultText = "Admin 不会查询 PDD 实时付款状态。"
|
||||
}
|
||||
|
||||
func orPlaceholder(s string) string {
|
||||
if s == "" {
|
||||
return placeholder
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
@@ -368,6 +369,66 @@ func TestGetTaskDetail_采购任务显示专有字段(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_采购成功独立显示PDD核单结果(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
insertTestTask(t, db, testTaskParams{
|
||||
taskID: "PUR-ORDER", taskType: model.TaskPurchase, status: model.TaskSucceeded,
|
||||
resultData: `{"purchase":{"order_no":"PDD-20260810-001","ordered_at":"2026-08-10T11:12:13Z","payment_status":"unpaid","match_status":"matched","order_submitted":true}}`,
|
||||
})
|
||||
|
||||
d, err := GetTaskDetail(db, "PUR-ORDER")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !d.HasPddOrder || d.PddOrderNo != "PDD-20260810-001" {
|
||||
t.Fatalf("PDD 订单编号没有结构化显示: %+v", d)
|
||||
}
|
||||
if d.PddOrderedAt != formatLocalTime("2026-08-10T11:12:13Z") {
|
||||
t.Errorf("UTC 下单时间应转为本地时间,实际 %q", d.PddOrderedAt)
|
||||
}
|
||||
if d.PddPaymentStatusText != "未付款(Client 上报时)" ||
|
||||
d.PddOrderResultText != "Admin 不会查询 PDD 实时付款状态。" {
|
||||
t.Errorf("付款状态说明不明确: status=%q help=%q",
|
||||
d.PddPaymentStatusText, d.PddOrderResultText)
|
||||
}
|
||||
if !d.HasResult || !strings.Contains(d.ResultData, `"order_no":"PDD-20260810-001"`) {
|
||||
t.Error("结构化展示后仍必须保留原始结果")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_核单结果状态分别显示(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
status model.TaskStatus
|
||||
resultData string
|
||||
want string
|
||||
}{
|
||||
{"等待上报", model.TaskClaimed, "", "等待 Client 核单上报。"},
|
||||
{"人工处理", model.TaskManualReview, "", "订单结果不确定,请结合错误信息人工核对。"},
|
||||
{"非法JSON", model.TaskSucceeded, `{`, "采购结果格式异常,请展开完整结果进行诊断。"},
|
||||
{"缺少purchase", model.TaskSucceeded, `{}`, "采购结果格式异常,请展开完整结果进行诊断。"},
|
||||
{"尚未匹配", model.TaskSucceeded, `{"purchase":{"match_status":"not_found"}}`, "本次结果没有已匹配的 PDD 订单。"},
|
||||
{"时间非法", model.TaskSucceeded, `{"purchase":{"order_no":"PDD-1","ordered_at":"2026-08-10 11:12","payment_status":"unpaid","match_status":"matched","order_submitted":true}}`, "采购结果中的下单时间格式异常,请展开完整结果进行诊断。"},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
taskID := fmt.Sprintf("PUR-STATE-%d", i)
|
||||
insertTestTask(t, db, testTaskParams{
|
||||
taskID: taskID, taskType: model.TaskPurchase,
|
||||
status: tc.status, resultData: tc.resultData,
|
||||
})
|
||||
d, err := GetTaskDetail(db, taskID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.HasPddOrder || d.PddOrderResultText != tc.want {
|
||||
t.Errorf("状态说明不对: HasPddOrder=%t text=%q", d.HasPddOrder, d.PddOrderResultText)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_采集任务不带采购专有字段(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
insertTestTask(t, db, testTaskParams{taskID: "COL-1", taskType: model.TaskCollect, status: model.TaskPending, pddGoodsID: "111"})
|
||||
@@ -382,6 +443,9 @@ func TestGetTaskDetail_采集任务不带采购专有字段(t *testing.T) {
|
||||
if d.SpecText != "" || d.QuantityText != "" || d.PriceLimitText != "" {
|
||||
t.Errorf("采集任务不该填充采购专有字段: spec=%q qty=%q price=%q", d.SpecText, d.QuantityText, d.PriceLimitText)
|
||||
}
|
||||
if d.HasPddOrder || d.PddOrderResultText != "" {
|
||||
t.Error("采集任务不应生成 PDD 核单结果展示")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTaskDetail_有错误信息时显示(t *testing.T) {
|
||||
|
||||
@@ -34,6 +34,20 @@
|
||||
{{end}}
|
||||
</dl>
|
||||
|
||||
{{if .IsPurchase}}
|
||||
<h3>PDD 核单结果</h3>
|
||||
{{if .HasPddOrder}}
|
||||
<dl class="detail">
|
||||
<dt>PDD 订单编号</dt><dd>{{.PddOrderNo}}</dd>
|
||||
<dt>下单时间</dt><dd>{{.PddOrderedAt}}</dd>
|
||||
<dt>上报时付款状态</dt><dd>{{.PddPaymentStatusText}}</dd>
|
||||
</dl>
|
||||
<p class="hint">{{.PddOrderResultText}}</p>
|
||||
{{else}}
|
||||
<p class="hint">{{.PddOrderResultText}}</p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .HasError}}
|
||||
<h3>错误</h3>
|
||||
<dl class="detail">
|
||||
|
||||
Reference in New Issue
Block a user