diff --git a/server/app/goauto/sybimport/resolve_keys.go b/server/app/goauto/sybimport/resolve_keys.go index 0f12284..596b8e8 100644 --- a/server/app/goauto/sybimport/resolve_keys.go +++ b/server/app/goauto/sybimport/resolve_keys.go @@ -56,6 +56,13 @@ func resyncShopeeProductKeys(tx *gorm.DB, shopeeProductID uint64, incomingRaw st Updates(map[string]any{"target_color": keys.Color, "target_size": keys.Size}).Error; err != nil { return sybspec.ParseResult{}, err } + // `[必须]` 改了明细的键就必须把新键补进档案。映射是按档案里的值建的, + // 档案没有 `黑色【長袖】` 这个条目,采购查映射就查不到,明细永远停在 + // 「规格待匹配」——而采购员点「一键匹配」匹到的是档案里剩下的旧键 + // `黑色`,看起来成功了却没有任何明细在用它。 + if err := mergeParsedSpec(tx, shopeeProductID, keys); err != nil { + return sybspec.ParseResult{}, err + } } return resolved[incomingRaw], nil } diff --git a/server/app/goauto/sybimport/resolve_keys_archive_test.go b/server/app/goauto/sybimport/resolve_keys_archive_test.go new file mode 100644 index 0000000..a0d7bc9 --- /dev/null +++ b/server/app/goauto/sybimport/resolve_keys_archive_test.go @@ -0,0 +1,77 @@ +package sybimport_test + +import ( + "context" + "encoding/json" + "testing" + + "go-admin/app/goauto/models" + "go-admin/app/goauto/shopeeproduct" + "go-admin/app/goauto/sybimport" +) + +func sleeveDetail(id uint64, spec string) sybimport.DetailInput { + raw, _ := json.Marshal(map[string]any{ + "id": id, "productQty": 1, "productPrice": 100.0, "productThumb": 1, + "productTitle": "襯衫", "productSpec": spec, "productId": 24377106095, + }) + return sybimport.DetailInput{ + ID: id, ProductID: 24377106095, ProductQty: 1, ProductPrice: 100.0, + ProductSpec: spec, ProductTitle: "襯衫", ProductThumb: 1, Raw: raw, + } +} + +// `[必须]` 消歧改了明细的键,就必须把新键补进档案。映射是按档案里的值建的, +// 档案没有 `黑色【長袖】` 这个条目,采购查映射就查不到,明细永远停在「规格待匹配」; +// 而采购员点「一键匹配」匹到的是档案里剩下的旧键 `黑色`,看起来成功了却没有任何 +// 明细在用它——线上 2026-09-17 正是这样(#301)。 +func TestDisambiguatedKeysReachTheArchive(t *testing.T) { + db := openTestDB(t) + order := realOrder() + + if _, err := sybimport.ApplyDetail(context.Background(), db, order, + sleeveDetail(900001, "黑色【短袖】,M 【建議42.5-47.5公斤】")); err != nil { + t.Fatal(err) + } + second, err := sybimport.ApplyDetail(context.Background(), db, order, + sleeveDetail(900002, "黑色【長袖】,5XL 【建議72.5-77.5公斤】")) + if err != nil { + t.Fatal(err) + } + if second.SYBProduct.ShopeeProductID == nil { + t.Fatal("未关联虾皮商品") + } + + var product models.ShopeeProduct + if err := db.First(&product, *second.SYBProduct.ShopeeProductID).Error; err != nil { + t.Fatal(err) + } + specs, err := shopeeproduct.Unmarshal(product.SpecsJSON) + if err != nil { + t.Fatal(err) + } + archived := map[string]bool{} + for _, dimension := range specs { + for _, value := range dimension.Values { + archived[value.Name] = true + } + } + + // 两个明细的键都必须能在档案里找到,否则映射无从建立。 + for _, want := range []string{"黑色【短袖】", "黑色【長袖】"} { + if !archived[want] { + t.Fatalf("档案缺少键 %q,现有键: %v", want, archived) + } + } + + // 明细自己的键也必须是拆开后的形式。 + var rows []models.SYBProduct + if err := db.Where("shopee_product_id = ?", *second.SYBProduct.ShopeeProductID).Find(&rows).Error; err != nil { + t.Fatal(err) + } + for _, row := range rows { + if row.TargetColor != "黑色【短袖】" && row.TargetColor != "黑色【長袖】" { + t.Fatalf("明细 %d 的键未消歧: %q", row.ID, row.TargetColor) + } + } +}