fix: 兼容相同顺运宝明细逐件回写 (#289)
This commit is contained in:
@@ -2,8 +2,10 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
@@ -164,6 +166,58 @@ func TestPlanInnerCodeRecords_本地没有SybOrder仍可直查远端生成计划
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanInnerCodeRecords_持久化现成多明细逐件绑定(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
now := model.NowISO()
|
||||
user := model.User{UserID: "INNER-CODE-MULTI-USER", Username: "inner-code-multi-user", PasswordHash: "test",
|
||||
Role: model.RoleAdmin, Status: model.UserActive, PasswordChangedAt: now, CreatedAt: now, UpdatedAt: now}
|
||||
if err := repository.CreateUser(db, user); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
record := model.InnerCodeImportRow{
|
||||
BusinessDate: "2026-08-22", SourceRow: 19, OrderNumber: "ORDER-MULTI-EXISTING",
|
||||
Stall: "A档#1", SourceSKURaw: "A档#1-黑色-M", SpecRaw: "黑色,M",
|
||||
SpecKey: NormalizeInnerCodeSpecKey("黑色,M"), InnerCode: "DK-1,DK-2",
|
||||
SourceDuplicateCount: 2, CreatedByUserID: user.UserID,
|
||||
}
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := repository.UpsertInnerCodeImportRow(tx, record, now); err != nil {
|
||||
tx.Rollback()
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var recordID int64
|
||||
if err := db.QueryRow(`SELECT id FROM syb_inner_code_records WHERE order_number=?`, record.OrderNumber).Scan(&recordID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
first := innerCodeTestItem(201, record.SpecRaw, map[string]any{"sku": record.SourceSKURaw, "variationSku": "A档#1", "innerExpCode": ""})
|
||||
second := innerCodeTestItem(202, record.SpecRaw, map[string]any{"sku": record.SourceSKURaw, "variationSku": "A档#1", "innerExpCode": ""})
|
||||
first.ProductQty, second.ProductQty = 1, 1
|
||||
reader := &orderQueryInnerCodeReader{
|
||||
rowsByOrder: map[string][]syb.StockRow{record.OrderNumber: {{ID: 200, Code: record.OrderNumber}}},
|
||||
detailsByID: map[int64]syb.StockDetail{200: {ID: 200, Code: record.OrderNumber, Details: []syb.DetailItem{second, first}}},
|
||||
}
|
||||
result, err := PlanInnerCodeRecords(context.Background(), db, reader, record.BusinessDate, []int64{recordID})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var status model.InnerCodeStatus
|
||||
var detailID int64
|
||||
var remoteItems string
|
||||
if err := db.QueryRow(`SELECT status,detail_id,remote_items_json FROM syb_inner_code_records WHERE id=?`, recordID).
|
||||
Scan(&status, &detailID, &remoteItems); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Ready != 1 || status != model.InnerCodeReady || detailID != first.ID || !strings.Contains(remoteItems, `"source":"existing_matched"`) {
|
||||
t.Fatalf("逐件绑定未持久化 result=%+v status=%s detail=%d items=%s", result, status, detailID, remoteItems)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanInnerCodeRows_精确与标准化规格均受档口约束(t *testing.T) {
|
||||
records := []model.InnerCodeRecord{
|
||||
{ID: 1, OrderNumber: "ORDER-1", Stall: "A档#027", SpecRaw: "A-027 黑色,M碼 建議45-55公斤", InnerCode: "DK1", SourceDuplicateCount: 1},
|
||||
@@ -223,6 +277,62 @@ func TestMatchInnerCodeItemsWithEvidence_重复和证据冲突均阻断(t *testi
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanInnerCodeRows_两个单件码复用两条相同现成明细(t *testing.T) {
|
||||
record := model.InnerCodeRecord{
|
||||
ID: 41, OrderNumber: "260820SS6E61GG", Stall: "優褲網購#0907",
|
||||
SourceSKURaw: "優褲網購#0907-灰色【小個子145-155CM】-2XL 【建議62-72kg】",
|
||||
SpecRaw: "灰色【小個子145-155CM】,2XL 【建議62-72kg】",
|
||||
InnerCode: "DK260822A130101,DK260822A130301", SourceDuplicateCount: 2,
|
||||
}
|
||||
first := innerCodeTestItem(147679521, record.SpecRaw, map[string]any{
|
||||
"sku": record.SourceSKURaw, "variationSku": "上寮-优裤网购#907#(&17)",
|
||||
"innerExpCode": "", "purchasePlatform": "", "purchaseCode": "",
|
||||
})
|
||||
first.ProductQty = 1
|
||||
second := innerCodeTestItem(147679527, record.SpecRaw, map[string]any{
|
||||
"sku": record.SourceSKURaw, "variationSku": "上寮-优裤网购#907#(&17)",
|
||||
"innerExpCode": "", "purchasePlatform": "", "purchaseCode": "",
|
||||
})
|
||||
second.ProductQty = 1
|
||||
|
||||
plans := planInnerCodeRows([]model.InnerCodeRecord{record},
|
||||
map[string][]int64{record.OrderNumber: {76544812}},
|
||||
map[int64]syb.StockDetail{76544812: {ID: 76544812, Details: []syb.DetailItem{second, first}}})
|
||||
if len(plans) != 1 || plans[0].Status != model.InnerCodeReady || plans[0].DetailID != first.ID {
|
||||
t.Fatalf("多明细逐件规划失败: %+v", plans)
|
||||
}
|
||||
var items []innerCodeRemoteItem
|
||||
if err := json.Unmarshal([]byte(plans[0].RemoteItemsJSON), &items); err != nil {
|
||||
t.Fatalf("逐件规划 JSON 无效: %v raw=%q", err, plans[0].RemoteItemsJSON)
|
||||
}
|
||||
want := []innerCodeRemoteItem{
|
||||
{Code: "DK260822A130101", DetailID: first.ID, Source: innerCodeRemoteSourceExistingMatched, Status: "planned"},
|
||||
{Code: "DK260822A130301", DetailID: second.ID, Source: innerCodeRemoteSourceExistingMatched, Status: "planned"},
|
||||
}
|
||||
if !reflect.DeepEqual(items, want) {
|
||||
t.Fatalf("逐件绑定不稳定: got=%+v want=%+v", items, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanInnerCodeRows_相同候选数与单件码数不一致仍阻断(t *testing.T) {
|
||||
record := model.InnerCodeRecord{ID: 42, OrderNumber: "ORDER-DUP", Stall: "A档#1",
|
||||
SourceSKURaw: "A档#1-黑色-M", SpecRaw: "黑色,M",
|
||||
InnerCode: "DK-1,DK-2", SourceDuplicateCount: 2}
|
||||
details := make([]syb.DetailItem, 3)
|
||||
for index := range details {
|
||||
details[index] = innerCodeTestItem(int64(index+1), record.SpecRaw, map[string]any{
|
||||
"sku": record.SourceSKURaw, "variationSku": "A档#1", "innerExpCode": "",
|
||||
})
|
||||
details[index].ProductQty = 1
|
||||
}
|
||||
plans := planInnerCodeRows([]model.InnerCodeRecord{record},
|
||||
map[string][]int64{record.OrderNumber: {100}},
|
||||
map[int64]syb.StockDetail{100: {ID: 100, Details: details}})
|
||||
if len(plans) != 1 || plans[0].Status != model.InnerCodeSkipped || plans[0].RemoteItemsJSON != "" {
|
||||
t.Fatalf("真实重复候选不应自动规划: %+v", plans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInnerCodeStallMatches_中文括号货号与数字前导零(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user