package service import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wangjia/jiu/backend/internal/model" "github.com/wangjia/jiu/backend/testutil" ) // BackfillPricingColumns:旧列(unit_price/total_price/total_amount)拷入新列,幂等。 // 测试库 DDL 已是新列,这里手动补建旧列模拟升级前的生产库形态。 func TestBackfillPricingColumns_Idempotent(t *testing.T) { db := testutil.SetupTestDB() for _, ddl := range []string{ `ALTER TABLE stock_in_items ADD COLUMN unit_price REAL DEFAULT 0`, `ALTER TABLE stock_in_items ADD COLUMN total_price REAL DEFAULT 0`, `ALTER TABLE stock_in_orders ADD COLUMN total_amount REAL DEFAULT 0`, `ALTER TABLE stock_out_items ADD COLUMN unit_price REAL DEFAULT 0`, `ALTER TABLE stock_out_items ADD COLUMN total_price REAL DEFAULT 0`, `ALTER TABLE stock_out_orders ADD COLUMN total_amount REAL DEFAULT 0`, } { require.NoError(t, db.Exec(ddl).Error) } shop := testutil.CreateTestShop(db, "MIG1") // 升级前形态:只有旧列有值(新列 0) inOrder := model.StockInOrder{TenantBase: model.TenantBase{ShopID: shop.ID}, OrderNo: "R1", WarehouseID: 1, OperatorID: 1, Status: "approved"} require.NoError(t, db.Create(&inOrder).Error) db.Exec(`UPDATE stock_in_orders SET total_amount = 500 WHERE id = ?`, inOrder.ID) inItem := model.StockInItem{OrderID: inOrder.ID, ShopID: shop.ID, ProductID: 1, Quantity: 10} require.NoError(t, db.Create(&inItem).Error) db.Exec(`UPDATE stock_in_items SET unit_price = 50, total_price = 500 WHERE id = ?`, inItem.ID) outOrder := model.StockOutOrder{TenantBase: model.TenantBase{ShopID: shop.ID}, OrderNo: "C1", WarehouseID: 1, OperatorID: 1, Status: "approved"} require.NoError(t, db.Create(&outOrder).Error) db.Exec(`UPDATE stock_out_orders SET total_amount = 800 WHERE id = ?`, outOrder.ID) outItem := model.StockOutItem{OrderID: outOrder.ID, ShopID: shop.ID, ProductID: 1, Quantity: 2, SalePrice: 400} require.NoError(t, db.Create(&outItem).Error) db.Exec(`UPDATE stock_out_items SET unit_price = 355, total_price = 710, sale_amount = 0 WHERE id = ?`, outItem.ID) // 待定价出库单:sale_price=0 → sale_amount/profit 均应保持 0 pendOrder := model.StockOutOrder{TenantBase: model.TenantBase{ShopID: shop.ID}, OrderNo: "C2", WarehouseID: 1, OperatorID: 1, Status: "approved"} require.NoError(t, db.Create(&pendOrder).Error) pendItem := model.StockOutItem{OrderID: pendOrder.ID, ShopID: shop.ID, ProductID: 1, Quantity: 3} require.NoError(t, db.Create(&pendItem).Error) db.Exec(`UPDATE stock_out_items SET unit_price = 100, total_price = 300 WHERE id = ?`, pendItem.ID) BackfillPricingColumns(db) var gotIn model.StockInItem db.First(&gotIn, inItem.ID) assert.Equal(t, float64(50), gotIn.CostPrice) assert.Equal(t, float64(500), gotIn.CostAmount) var gotInOrder model.StockInOrder db.First(&gotInOrder, inOrder.ID) assert.Equal(t, float64(500), gotInOrder.CostTotal) var gotOut model.StockOutItem db.First(&gotOut, outItem.ID) assert.Equal(t, float64(355), gotOut.CostPrice) assert.Equal(t, float64(710), gotOut.CostAmount) assert.Equal(t, float64(800), gotOut.SaleAmount) // 400×2 var gotOutOrder model.StockOutOrder db.First(&gotOutOrder, outOrder.ID) assert.Equal(t, float64(800), gotOutOrder.SaleTotal) assert.Equal(t, float64(90), gotOutOrder.ProfitTotal) // (400-355)×2 var gotPend model.StockOutItem db.First(&gotPend, pendItem.ID) assert.Equal(t, float64(100), gotPend.CostPrice) assert.Equal(t, float64(0), gotPend.SaleAmount) var gotPendOrder model.StockOutOrder db.First(&gotPendOrder, pendOrder.ID) assert.Equal(t, float64(0), gotPendOrder.ProfitTotal) // 幂等:第二次执行不改变结果(人为改一个新列值验证不会被旧值覆盖——新列非 0 即跳过) db.Exec(`UPDATE stock_out_items SET sale_price = 450, sale_amount = 900 WHERE id = ?`, outItem.ID) BackfillPricingColumns(db) var again model.StockOutItem db.First(&again, outItem.ID) assert.Equal(t, float64(900), again.SaleAmount) // 未被回填覆盖 var againOrder model.StockOutOrder db.First(&againOrder, outOrder.ID) assert.Equal(t, float64(800), againOrder.SaleTotal) // 已有值不重拷 }