diff --git a/server/app/goauto/purchase/ai_match_eligibility.go b/server/app/goauto/purchase/ai_match_eligibility.go index 04fbb3b..094a664 100644 --- a/server/app/goauto/purchase/ai_match_eligibility.go +++ b/server/app/goauto/purchase/ai_match_eligibility.go @@ -32,7 +32,10 @@ type skuCombinationRow struct { } func sybSpecsTrusted(syb models.SYBProduct) bool { - return syb.ParseStatus == models.SYBParseStatusSuccess || syb.ManuallyConfirmed + if syb.ParseStatus == models.SYBParseStatusFailed { + return false + } + return strings.TrimSpace(syb.TargetColor) != "" || strings.TrimSpace(syb.TargetSize) != "" } func (s *Service) loadLatestSKUCombinations(ctx context.Context, pddIDs []uint64, dataset *batchPreviewDataset) error { diff --git a/server/app/goauto/purchase/batch_spec_match_test.go b/server/app/goauto/purchase/batch_spec_match_test.go index bcd608e..ab936d2 100644 --- a/server/app/goauto/purchase/batch_spec_match_test.go +++ b/server/app/goauto/purchase/batch_spec_match_test.go @@ -175,10 +175,10 @@ func TestBatchSpecMatchPersistsExactMatchBeforePurchaseCreation(t *testing.T) { } } -func TestManuallyConfirmedUncertainSpecsCanBeMatchedBeforePurchase(t *testing.T) { +func TestExtractedUncertainSpecsCanBeMatchedBeforePurchase(t *testing.T) { service, f := exactBatchSpecFixture(t) if err := service.DB.Model(&models.SYBProduct{}).Where("id = ?", f.syb.ID).Updates(map[string]any{ - "parse_status": models.SYBParseStatusUncertain, "manually_confirmed": true, + "parse_status": models.SYBParseStatusUncertain, "manually_confirmed": false, }).Error; err != nil { t.Fatal(err) } @@ -187,15 +187,15 @@ func TestManuallyConfirmedUncertainSpecsCanBeMatchedBeforePurchase(t *testing.T) before, err := service.BatchPreview(context.Background(), BatchPreviewRequest{SYBProductIDs: []uint64{f.syb.ID}}) if err != nil || len(before.Items) != 1 || before.Items[0].Eligible || !before.Items[0].AIMatchEligible || before.Items[0].ProcessStage != ProcessStageColorMapping { - t.Fatalf("manually confirmed specs did not enter matching: %+v err=%v", before, err) + t.Fatalf("extracted uncertain specs did not enter matching: %+v err=%v", before, err) } matched, err := service.BatchSpecMatch(context.Background(), BatchSpecMatchRequest{SYBProductIDs: []uint64{f.syb.ID}}) if err != nil || matched.AutoConfirmedCount != 1 || matcher.calls != 0 { - t.Fatalf("manual correction did not allow exact match: %+v calls=%d err=%v", matched, matcher.calls, err) + t.Fatalf("extracted uncertain specs did not allow exact match: %+v calls=%d err=%v", matched, matcher.calls, err) } after, err := service.BatchPreview(context.Background(), BatchPreviewRequest{SYBProductIDs: []uint64{f.syb.ID}}) if err != nil || !after.Items[0].Eligible || after.Items[0].ProcessStage != ProcessStagePurchaseReady { - t.Fatalf("saved mapping did not unlock manual correction: %+v err=%v", after, err) + t.Fatalf("saved mapping did not unlock extracted uncertain specs: %+v err=%v", after, err) } } diff --git a/server/app/goauto/purchase/batch_test.go b/server/app/goauto/purchase/batch_test.go index b074866..2b0b79e 100644 --- a/server/app/goauto/purchase/batch_test.go +++ b/server/app/goauto/purchase/batch_test.go @@ -44,6 +44,27 @@ func TestBatchPreviewUsesPDDPriceAndExplainsIneligibleRows(t *testing.T) { } } +func TestSybSpecsTrustedOnlyBlocksFailedOrEmptyExtraction(t *testing.T) { + tests := []struct { + name string + syb models.SYBProduct + trust bool + }{ + {"success", models.SYBProduct{ParseStatus: models.SYBParseStatusSuccess, TargetColor: "黑色", TargetSize: "XL"}, true}, + {"uncertain with color", models.SYBProduct{ParseStatus: models.SYBParseStatusUncertain, TargetColor: "套装"}, true}, + {"uncertain with size", models.SYBProduct{ParseStatus: models.SYBParseStatusUncertain, TargetSize: "均码"}, true}, + {"failed with values", models.SYBProduct{ParseStatus: models.SYBParseStatusFailed, TargetColor: "黑色"}, false}, + {"uncertain without values", models.SYBProduct{ParseStatus: models.SYBParseStatusUncertain}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := sybSpecsTrusted(tt.syb); got != tt.trust { + t.Fatalf("sybSpecsTrusted=%v, want %v", got, tt.trust) + } + }) + } +} + func TestBatchPreviewExposesIndependentCollectionEligibility(t *testing.T) { db := testDB(t) fixture := seed(t, db, liveCaps(), true)